Ejemplo n.º 1
0
/*-------------------------------------------------------------------------
  TSPluginInit
  Function called at plugin init time

  Input:
    argc  number of args
    argv  list vof args
  Output :
  Return Value:
  -------------------------------------------------------------------------*/
void
TSPluginInit(int argc, const char *argv[])
{
  TSPluginRegistrationInfo info;
  int i;
  TSReturnCode retval;

  info.plugin_name = "psi";
  info.vendor_name = "Apache";
  info.support_email = "";

  if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {
    TSError("Plugin registration failed.\n");
  }

  if (!check_ts_version()) {
    TSError("Plugin requires Traffic Server 3.0 or later\n");
    return;
  }

  /* Initialize the psi directory = <plugin_path>/include */
  sprintf(psi_directory, "%s/%s", TSPluginDirGet(), PSI_PATH);

  /* create an TSTextLogObject to log any psi include */
  retval = TSTextLogObjectCreate("psi", TS_LOG_MODE_ADD_TIMESTAMP, &log);
  if (retval == TS_ERROR) {
    TSError("Failed creating log for psi plugin");
    log = NULL;
  }

  /* Create working threads */
  thread_init();
  init_queue(&job_queue);

  for (i = 0; i < NB_THREADS; i++) {
    char *thread_name = (char *) TSmalloc(64);
    sprintf(thread_name, "Thread[%d]", i);
    if (!TSThreadCreate((TSThreadFunc) thread_loop, thread_name)) {
      TSError("[TSPluginInit] Error while creating threads");
      return;
    }
  }

  TSHttpHookAdd(TS_HTTP_READ_RESPONSE_HDR_HOOK, TSContCreate(read_response_handler, TSMutexCreate()));
  TSDebug(DBG_TAG, "Plugin started");
}
Ejemplo n.º 2
0
static void
handle_txn_start(TSCont contp ATS_UNUSED, TSHttpTxn txnp)
{
  TSCont txn_contp;
  cdata *cd;

  txn_contp = TSContCreate((TSEventFunc)blacklist_plugin, TSMutexCreate());
  /* create the data that'll be associated with the continuation */
  cd = (cdata *)TSmalloc(sizeof(cdata));
  TSContDataSet(txn_contp, cd);

  cd->txnp = txnp;

  TSHttpTxnHookAdd(txnp, TS_HTTP_OS_DNS_HOOK, txn_contp);
  TSHttpTxnHookAdd(txnp, TS_HTTP_TXN_CLOSE_HOOK, txn_contp);

  TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
}
Ejemplo n.º 3
0
static void
handle_response(TSHttpTxn txnp, TSCont contp ATS_UNUSED)
{
  TSMBuffer bufp;
  TSMLoc hdr_loc;
  TSMLoc url_loc;
  char *url_str;
  char *buf;
  int url_length;

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

  TSHttpHdrStatusSet(bufp, hdr_loc, TS_HTTP_STATUS_FORBIDDEN);
  TSHttpHdrReasonSet(bufp, hdr_loc, TSHttpHdrReasonLookup(TS_HTTP_STATUS_FORBIDDEN),
                     strlen(TSHttpHdrReasonLookup(TS_HTTP_STATUS_FORBIDDEN)));

  if (TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
    TSError("[%s] Couldn't retrieve client request header", PLUGIN_NAME);
    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
    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;
  }

  buf = (char *)TSmalloc(4096);

  url_str = TSUrlStringGet(bufp, url_loc, &url_length);
  sprintf(buf, "You are forbidden from accessing \"%s\"\n", url_str);
  TSfree(url_str);
  TSHandleMLocRelease(bufp, hdr_loc, url_loc);
  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);

  TSHttpTxnErrorBodySet(txnp, buf, strlen(buf), NULL);

done:
  TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
}
Ejemplo n.º 4
0
static config_holder_t* new_config_holder(const char* path) {
	char default_config_file[1024];
	config_holder_t* config_holder = TSmalloc(sizeof(config_holder_t));
	config_holder->config_path = 0;
	config_holder->config = 0;
	config_holder->last_load = 0;
	//	TSmalloc(32);
	//
	if(path) {
		config_holder->config_path = nstr(path);
	} else {
		/* Default config file of plugins/cacheurl.config */
		//		sprintf(default_config_file, "%s/astats.config", TSPluginDirGet());
		sprintf(default_config_file, "%s/"DEFAULT_CONFIG_NAME, TSConfigDirGet());
		config_holder->config_path = nstr(default_config_file);
	}
	load_config_file(config_holder);
	return config_holder;
}
Ejemplo n.º 5
0
static int
ts_lua_sleep(lua_State * L)
{
  int sec;
  TSAction action;
  TSCont contp;
  ts_lua_http_intercept_item *node;
  ts_lua_http_intercept_ctx *ictx;

  ictx = ts_lua_get_http_intercept_ctx(L);
  sec = luaL_checknumber(L, 1);

  contp = TSContCreate(ts_lua_sleep_handler, TSContMutexGet(ictx->contp));
  action = TSContSchedule(contp, sec * 1000, TS_THREAD_POOL_DEFAULT);

  node = (ts_lua_http_intercept_item *) TSmalloc(sizeof(ts_lua_http_intercept_item));
  TS_LUA_ADD_INTERCEPT_ITEM(ictx, node, contp, ts_lua_sleep_cleanup, action);
  TSContDataSet(contp, node);

  return lua_yield(L, 0);
}
Ejemplo n.º 6
0
TSReturnCode
TSRemapNewInstance(int argc, char **argv, void **ih, char *errbuf, int errbuf_size)
{
  int i;
  char *ptr;
  secure_link_info *sli;

  // squash unused variable warnings ...
  (void)errbuf;
  (void)errbuf_size;

  sli = (secure_link_info *)TSmalloc(sizeof(secure_link_info));
  sli->secret = NULL;
  sli->strict = 0;

  for(i = 2; i < argc; i++) {
    if((ptr = strchr(argv[i], ':')) != NULL) {
      *ptr++ = '\0';
      if(strcmp(argv[i], "secret") == 0) {
        if(sli->secret != NULL) {
          TSfree(sli->secret);
        }
        sli->secret = TSstrdup(ptr);
      } else if(strcmp(argv[i], "policy") == 0) {
        sli->strict = !strcasecmp(ptr, "strict");
      } else {
        TSDebug(PLUGIN_NAME, "Unknown parameter [%s]", argv[i]);
      }
    } else {
      TSError("Invalid parameter [%s]", argv[i]);
    }
  }

  if(sli->secret == NULL) {
    sli->secret = TSstrdup("");
  }

  *ih = (void *)sli;
  return TS_SUCCESS;
}
static char *
gen_header(char *status_str, char *mime, int *header_len)
{
  TSHttpStatus status;
  char * buf = NULL;

  status = atoi(status_str);
  if (status > 0 && status < 999) {
    const char* status_reason;
    int len = sizeof(HEADER_TEMPLATE) + 3 + 1;

    status_reason = TSHttpHdrReasonLookup(status);
    len += strlen(status_reason);
    len += strlen(mime);
    buf = TSmalloc(len);
    *header_len = snprintf(buf, len, HEADER_TEMPLATE, status, status_reason, mime);
  } else {
    *header_len = 0;
  }

  return buf;
}
Ejemplo n.º 8
0
ts_lua_http_ctx *
ts_lua_create_http_ctx(ts_lua_main_ctx *main_ctx, ts_lua_instance_conf *conf)
{
    ts_lua_http_ctx     *http_ctx;
    lua_State           *L;
    lua_State           *l;

    L = main_ctx->lua;

    http_ctx = TSmalloc(sizeof(ts_lua_http_ctx));
    memset(http_ctx, 0, sizeof(ts_lua_http_ctx));

    http_ctx->lua = lua_newthread(L);
    l = http_ctx->lua;

    lua_pushlightuserdata(L, conf);
    lua_rawget(L, LUA_REGISTRYINDEX);

    /* new globals table for coroutine */
    lua_newtable(l);
    lua_pushvalue(l, -1);
    lua_setfield(l, -2, "_G"); 
    lua_newtable(l);
    lua_xmove(L, l, 1);
    lua_setfield(l, -2, "__index");
    lua_setmetatable(l, -2);

    lua_replace(l, LUA_GLOBALSINDEX);

    http_ctx->ref = luaL_ref(L, LUA_REGISTRYINDEX);

    http_ctx->mctx = main_ctx;

    ts_lua_set_http_ctx(http_ctx->lua, http_ctx);
    ts_lua_create_context_table(http_ctx->lua);

    return http_ctx;
}
static RequestInfo *
create_request_info(TSHttpTxn txn)
{
  RequestInfo *req_info;
  char *url;
  int url_len;
  TSMBuffer buf;
  TSMLoc loc;

  const struct sockaddr *sa;

  req_info = (RequestInfo *)TSmalloc(sizeof(RequestInfo));
  memset(req_info, 0, sizeof(RequestInfo));

  url                     = TSHttpTxnEffectiveUrlStringGet(txn, &url_len);
  req_info->effective_url = TSstrndup(url, url_len);
  TSfree(url);

  TSHttpTxnClientReqGet(txn, &buf, &loc);
  req_info->buf = TSMBufferCreate();
  TSHttpHdrClone(req_info->buf, buf, loc, &(req_info->http_hdr_loc));
  TSHandleMLocRelease(buf, TS_NULL_MLOC, loc);

  sa = TSHttpTxnClientAddrGet(txn);
  switch (sa->sa_family) {
  case AF_INET:
    memcpy(&req_info->client_addr.sin, sa, sizeof(struct sockaddr_in));
    break;
  case AF_INET6:
    memcpy(&req_info->client_addr.sin6, sa, sizeof(struct sockaddr_in6));
    break;
  default:
    break;
  }

  return req_info;
}
Ejemplo n.º 10
0
/*-------------------------------------------------------------------------
  cont_data_alloc
  Allocate and initialize a ContData structure associated to a transaction

  Input:
  Output:
  Return Value:
    Pointer on a new allocated ContData structure
  -------------------------------------------------------------------------*/
static ContData *
cont_data_alloc()
{
  ContData *data;

  data = (ContData *) TSmalloc(sizeof(ContData));
  data->magic = MAGIC_ALIVE;
  data->output_vio = NULL;
  data->output_buffer = NULL;
  data->output_reader = NULL;

  data->psi_buffer = NULL;
  data->psi_reader = NULL;
  data->psi_filename[0] = '\0';
  data->psi_filename_len = 0;
  data->psi_success = 0;

  data->parse_state = PARSE_SEARCH;

  data->state = STATE_READ_DATA;
  data->transform_bytes = 0;

  return data;
}
Ejemplo n.º 11
0
static void process_data(TSCont contp, ibd_ctx* ibd)
{
  TSVConn output_conn;
  TSIOBuffer buf_test;
  TSVIO input_vio;
  ib_txn_ctx *data;
  int64_t towrite;
  int64_t avail;
  int first_time = 0;
  char *bufp = NULL;

  TSDebug("ironbee", "Entering process_data()");
  /* Get the output (downstream) vconnection where we'll write data to. */

  output_conn = TSTransformOutputVConnGet(contp);

  /* Get the write VIO for the write operation that was performed on
   * ourself. This VIO contains the buffer that we are to read from
   * as well as the continuation we are to call when the buffer is
   * empty. This is the input VIO (the write VIO for the upstream
   * vconnection).
   */
  input_vio = TSVConnWriteVIOGet(contp);

  data = TSContDataGet(contp);
  if (!ibd->data->output_buffer) {
    first_time = 1;

    ibd->data->output_buffer = TSIOBufferCreate();
    ibd->data->output_reader = TSIOBufferReaderAlloc(ibd->data->output_buffer);
    TSDebug("ironbee", "\tWriting %d bytes on VConn", TSVIONBytesGet(input_vio));
    ibd->data->output_vio = TSVConnWrite(output_conn, contp, ibd->data->output_reader, INT64_MAX);
  }
  if (ibd->data->buf) {
    /* this is the second call to us, and we have data buffered.
     * Feed buffered data to ironbee
     */
        ib_conndata_t icdata;
          icdata.ib = ironbee;
          icdata.mp = data->ssn->iconn->mp;
          icdata.conn = data->ssn->iconn;
          icdata.dalloc = ibd->data->buflen;
          icdata.dlen = ibd->data->buflen;
          icdata.data = (uint8_t *)ibd->data->buf;
          (*ibd->ibd->ib_notify)(ironbee, &icdata);
    TSfree(ibd->data->buf);
    ibd->data->buf = NULL;
    ibd->data->buflen = 0;
  }

  /* test for input data */
  buf_test = TSVIOBufferGet(input_vio);

  if (!buf_test) {
    TSDebug("ironbee", "No more data, finishing");
    TSVIONBytesSet(ibd->data->output_vio, TSVIONDoneGet(input_vio));
    TSVIOReenable(ibd->data->output_vio);
    /* FIXME - is this right here - can conn data be kept across reqs? */
    ibd->data->output_buffer = NULL;
    ibd->data->output_reader = NULL;
    ibd->data->output_vio = NULL;
    return;
  }

  /* Determine how much data we have left to read. For this null
   * transform plugin this is also the amount of data we have left
   * to write to the output connection.
   */
  towrite = TSVIONTodoGet(input_vio);
  TSDebug("ironbee", "\ttoWrite is %" PRId64 "", towrite);

  if (towrite > 0) {
    /* The amount of data left to read needs to be truncated by
     * the amount of data actually in the read buffer.
     */

    /* first time through, we have to buffer the data until
     * after the headers have been sent.  Ugh!
     */
    if (first_time) {
      bufp = ibd->data->buf = TSmalloc(towrite);
      ibd->data->buflen = towrite;
    }
    
    avail = TSIOBufferReaderAvail(TSVIOReaderGet(input_vio));
    TSDebug("ironbee", "\tavail is %" PRId64 "", avail);
    if (towrite > avail) {
      towrite = avail;
    }

    if (towrite > 0) {
      int btowrite = towrite;
      /* Copy the data from the read buffer to the output buffer. */
      TSIOBufferCopy(TSVIOBufferGet(ibd->data->output_vio), TSVIOReaderGet(input_vio), towrite, 0);

      /* feed the data to ironbee, and consume them */
      while (btowrite > 0) {
        ib_conndata_t icdata;
        int64_t ilength;
        TSIOBufferReader input_reader = TSVIOReaderGet(input_vio);
        TSIOBufferBlock blkp = TSIOBufferReaderStart(input_reader);
        const char *ibuf = TSIOBufferBlockReadStart(blkp, input_reader, &ilength);

        /* feed it to ironbee or to buffer */
        if (first_time) {
          memcpy(bufp, ibuf, ilength);
          bufp += ilength;
        }
        else {
          icdata.ib = ironbee;
          icdata.mp = data->ssn->iconn->mp;
          icdata.conn = data->ssn->iconn;
          icdata.dalloc = ilength;
          icdata.dlen = ilength;
          icdata.data = (uint8_t *)ibuf;
          (*ibd->ibd->ib_notify)(ironbee, &icdata);
        }
  //"response", TSHttpTxnClientRespGet, ib_state_notify_conn_data_out
  //      ib_state_notify_conn_data_out(ironbee, &icdata);

        /* and mark it as all consumed */
        btowrite -= ilength;
        TSIOBufferReaderConsume(input_reader, ilength);
        TSVIONDoneSet(input_vio, TSVIONDoneGet(input_vio) + ilength);
      }
    }
  }

  /* Now we check the input VIO to see if there is data left to
   * read.
   */
  if (TSVIONTodoGet(input_vio) > 0) {
    if (towrite > 0) {
      /* If there is data left to read, then we reenable the output
       * connection by reenabling the output VIO. This will wake up
       * the output connection and allow it to consume data from the
       * output buffer.
       */
      TSVIOReenable(ibd->data->output_vio);

      /* Call back the input VIO continuation to let it know that we
       * are ready for more data.
       */
      TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_READY, input_vio);
    }
  } else {
    /* If there is no data left to read, then we modify the output
     * VIO to reflect how much data the output connection should
     * expect. This allows the output connection to know when it
     * is done reading. We then reenable the output connection so
     * that it can consume the data we just gave it.
     */
    TSVIONBytesSet(ibd->data->output_vio, TSVIONDoneGet(input_vio));
    TSVIOReenable(ibd->data->output_vio);

    /* Call back the input VIO continuation to let it know that we
     * have completed the write operation.
     */
    TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_COMPLETE, input_vio);
  }
}
Ejemplo n.º 12
0
static int
ts_lua_add_hook(lua_State *L)
{
    int                     type;
    int                     entry;

    TSVConn                 connp;
    ts_lua_http_ctx         *http_ctx;
    ts_lua_transform_ctx    *transform_ctx;

    http_ctx = ts_lua_get_http_ctx(L);

    entry = lua_tointeger(L, 1);            // get hook id

    type = lua_type(L, 2);
    if (type != LUA_TFUNCTION)
        return 0;

    switch (entry) {

    case TS_LUA_HOOK_CACHE_LOOKUP_COMPLETE:
        TSHttpTxnHookAdd(http_ctx->txnp, TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK, http_ctx->main_contp);
        lua_pushvalue(L, 2);
        lua_setglobal(L, TS_LUA_FUNCTION_CACHE_LOOKUP_COMPLETE);
        break;

    case TS_LUA_HOOK_SEND_REQUEST_HDR:
        TSHttpTxnHookAdd(http_ctx->txnp, TS_HTTP_SEND_REQUEST_HDR_HOOK, http_ctx->main_contp);
        lua_pushvalue(L, 2);
        lua_setglobal(L, TS_LUA_FUNCTION_SEND_REQUEST);
        break;

    case TS_LUA_HOOK_READ_RESPONSE_HDR:
        TSHttpTxnHookAdd(http_ctx->txnp, TS_HTTP_READ_RESPONSE_HDR_HOOK, http_ctx->main_contp);
        lua_pushvalue(L, 2);
        lua_setglobal(L, TS_LUA_FUNCTION_READ_RESPONSE);
        break;

    case TS_LUA_HOOK_SEND_RESPONSE_HDR:
        TSHttpTxnHookAdd(http_ctx->txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, http_ctx->main_contp);
        lua_pushvalue(L, 2);
        lua_setglobal(L, TS_LUA_FUNCTION_SEND_RESPONSE);
        break;

    case TS_LUA_REQUEST_TRANSFORM:
    case TS_LUA_RESPONSE_TRANSFORM:
        transform_ctx = (ts_lua_transform_ctx*)TSmalloc(sizeof(ts_lua_transform_ctx));
        memset(transform_ctx, 0, sizeof(ts_lua_transform_ctx));
        transform_ctx->hctx = http_ctx;

        connp = TSTransformCreate(ts_lua_transform_entry, http_ctx->txnp);
        TSContDataSet(connp, transform_ctx);

        if (entry == TS_LUA_REQUEST_TRANSFORM) {
            TSHttpTxnHookAdd(http_ctx->txnp, TS_HTTP_REQUEST_TRANSFORM_HOOK, connp);
        } else {
            TSHttpTxnHookAdd(http_ctx->txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK, connp);
        }

        lua_pushlightuserdata(L, transform_ctx);
        lua_pushvalue(L, 2);
        lua_rawset(L, LUA_GLOBALSINDEX);
        break;

    default:
        break;
    }

    return 0;
}
Ejemplo n.º 13
0
static int ironbee_plugin(TSCont contp, TSEvent event, void *edata)
{
  TSVConn connp;
  TSCont mycont;
  TSHttpTxn txnp = (TSHttpTxn) edata;
  TSHttpSsn ssnp = (TSHttpSsn) edata;
  ib_txn_ctx *txndata;
  ib_ssn_ctx *ssndata;

  TSDebug("ironbee", "Entering ironbee_plugin with %d", event);
  switch (event) {

  /* CONNECTION */
  case TS_EVENT_HTTP_SSN_START:
    /* start of connection */
    /* But we can't initialise conn stuff here, because there's
     * no API to get the connection stuff required by ironbee
     * at this point.  So instead, intercept the first TXN
     *
     * what we can and must do: create a new contp whose
     * lifetime is our ssn
     */
    mycont = TSContCreate(ironbee_plugin, NULL);
    TSHttpSsnHookAdd (ssnp, TS_HTTP_TXN_START_HOOK, mycont);
    TSContDataSet(mycont, NULL);

    TSHttpSsnHookAdd (ssnp, TS_HTTP_SSN_CLOSE_HOOK, mycont);

    TSHttpSsnReenable (ssnp, TS_EVENT_HTTP_CONTINUE);
    break;
  case TS_EVENT_HTTP_TXN_START:
    /* start of Request */
    /* First req on a connection, we set up conn stuff */
    ssndata = TSContDataGet(contp);
    if (ssndata == NULL) {
      ib_conn_t *iconn = NULL;
      ib_status_t rc;
      rc = ib_conn_create(ironbee, &iconn, contp);
      if (rc != IB_OK) {
        TSError("ironbee", "ib_conn_create: %d\n", rc);
        return rc; // FIXME - figure out what to do
      }
      ssndata = TSmalloc(sizeof(ib_ssn_ctx));
      memset(ssndata, 0, sizeof(ib_ssn_ctx));
      ssndata->iconn = iconn;
      ssndata->txnp = txnp;
      TSContDataSet(contp, ssndata);
      ib_state_notify_conn_opened(ironbee, iconn);
    }

    /* create a txn cont (request ctx) */
    mycont = TSContCreate(ironbee_plugin, NULL);
    txndata = TSmalloc(sizeof(ib_txn_ctx));
    memset(txndata, 0, sizeof(ib_txn_ctx));
    txndata->ssn = ssndata;
    txndata->txnp = txnp;
    TSContDataSet(mycont, txndata);

    /* With both of these, SSN_CLOSE gets called first.
     * I must be misunderstanding SSN
     * So hook it all to TXN
     */
    TSHttpTxnHookAdd(txnp, TS_HTTP_TXN_CLOSE_HOOK, mycont);

    /* Hook to process responses */
    TSHttpTxnHookAdd(txnp, TS_HTTP_READ_RESPONSE_HDR_HOOK, mycont);

    /* Hook to process requests */
    TSHttpTxnHookAdd(txnp, TS_HTTP_READ_REQUEST_HDR_HOOK, mycont);

    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
    break;

  /* HTTP RESPONSE */
  case TS_EVENT_HTTP_READ_RESPONSE_HDR:
    txndata = TSContDataGet(contp);

    /* hook to examine output headers */
    /* Not sure why we can't do it right now, but it seems headers
     * are not yet available.
     * Can we use another case switch in this function?
     */
    TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp);

    /* hook an output filter to watch data */
    connp = TSTransformCreate(out_data_event, txnp);
    TSContDataSet(connp, txndata);
    TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK, connp);

    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
    break;

  /* hook for processing response headers */
  case TS_EVENT_HTTP_SEND_RESPONSE_HDR:
    txndata = TSContDataGet(contp);
    process_hdr(txndata, txnp, &ironbee_direction_resp);
    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
    break;

  /* HTTP REQUEST */
  case TS_EVENT_HTTP_READ_REQUEST_HDR:
    txndata = TSContDataGet(contp);

    /* hook to examine output headers */
    /* Not sure why we can't do it right now, but it seems headers
     * are not yet available.
     * Can we use another case switch in this function?
     */
    //TSHttpTxnHookAdd(txnp, TS_HTTP_OS_DNS_HOOK, contp);
    TSHttpTxnHookAdd(txnp, TS_HTTP_PRE_REMAP_HOOK, contp);

    /* hook an input filter to watch data */
    connp = TSTransformCreate(in_data_event, txnp);
    TSContDataSet(connp, txndata);
    TSHttpTxnHookAdd(txnp, TS_HTTP_REQUEST_TRANSFORM_HOOK, connp);

    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
    break;

  /* hook for processing incoming request/headers */
  case TS_EVENT_HTTP_PRE_REMAP:
    txndata = TSContDataGet(contp);
    process_hdr(txndata, txnp, &ironbee_direction_req);
    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
    break;


  /* CLEANUP EVENTS */
  case TS_EVENT_HTTP_TXN_CLOSE:
    TSDebug("ironbee", "TXN Close: %x\n", contp);
    ib_txn_ctx_destroy(TSContDataGet(contp));
    TSContDataSet(contp, NULL);
    TSContDestroy(contp);
    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
    break;

  case TS_EVENT_HTTP_SSN_CLOSE:
    TSDebug("ironbee", "SSN Close: %x\n", contp);
    ib_ssn_ctx_destroy(TSContDataGet(contp));
    TSContDestroy(contp);
    TSHttpSsnReenable(ssnp, TS_EVENT_HTTP_CONTINUE);
    break;

  /* if we get here we've got a bug */
  default:
    TSError("BUG: unhandled event %d in ironbee_plugin\n", event);
    break;
  }

  return 0;
}
Ejemplo n.º 14
0
static void
handle_dns(TSHttpTxn txnp, TSCont contp ATS_UNUSED)
{
  TSMBuffer bufp;
  TSMLoc hdr_loc;

  TSIOBuffer output_buffer;
  TSIOBufferReader reader;
  int total_avail;

  TSIOBufferBlock block;
  const char *block_start;
  int64_t block_avail;

  char *output_string;
  int64_t output_len;

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

  output_buffer = TSIOBufferCreate();
  reader        = TSIOBufferReaderAlloc(output_buffer);

  /* This will print  just MIMEFields and not
     the http request line */
  TSDebug(PLUGIN_NAME, "Printing the hdrs ... ");
  TSMimeHdrPrint(bufp, hdr_loc, output_buffer);

  if (TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc) == TS_ERROR) {
    TSDebug(PLUGIN_NAME, "non-fatal: error releasing MLoc");
    TSError("[%s] non-fatal: Couldn't release MLoc", PLUGIN_NAME);
  }

  /* Find out how the big the complete header is by
     seeing the total bytes in the buffer.  We need to
     look at the buffer rather than the first block to
     see the size of the entire header */
  total_avail = TSIOBufferReaderAvail(reader);

  /* Allocate the string with an extra byte for the string
     terminator */
  output_string = (char *)TSmalloc(total_avail + 1);
  output_len    = 0;

  /* We need to loop over all the buffer blocks to make
     sure we get the complete header since the header can
     be in multiple blocks */
  block = TSIOBufferReaderStart(reader);
  while (block) {
    block_start = TSIOBufferBlockReadStart(block, reader, &block_avail);

    /* We'll get a block pointer back even if there is no data
       left to read so check for this condition and break out of
       the loop. A block with no data to read means we've exhausted
       buffer of data since if there was more data on a later
       block in the chain, this block would have been skipped over */
    if (block_avail == 0) {
      break;
    }

    memcpy(output_string + output_len, block_start, block_avail);
    output_len += block_avail;

    /* Consume the data so that we get to the next block */
    TSIOBufferReaderConsume(reader, block_avail);

    /* Get the next block now that we've consumed the
       data off the last block */
    block = TSIOBufferReaderStart(reader);
  }

  /* Terminate the string */
  output_string[output_len] = '\0';
  output_len++;

  /* Free up the TSIOBuffer that we used to print out the header */
  TSIOBufferReaderFree(reader);
  TSIOBufferDestroy(output_buffer);

  /* Although I'd never do this a production plugin, printf
     the header so that we can see it's all there */
  TSDebug(PLUGIN_NAME, "%s", output_string);

  TSfree(output_string);

done:
  TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
}
Ejemplo n.º 15
0
static char * nstrl(const char *s, int len) {
	char *mys = (char *)TSmalloc(len + 1);
	memcpy(mys, s, len);
	mys[len] = 0;
	return mys;
}
Ejemplo n.º 16
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;
}
Ejemplo n.º 17
0
static int
ts_lua_cache_remove(lua_State *L)
{
    const char              *keystr, *optstr;
    size_t                  key_len, opt_len;
    int                     n;
    TSCont                  contp;
    TSCacheKey              key;
    TSAction                action;
    ts_lua_cont_info        *ci;
    ts_lua_async_item       *ai;
    ts_lua_cache_info       *info;

    ci = ts_lua_get_cont_info(L);
    if (ci == NULL)
        return 0;

    n = lua_gettop(L);
    if (n < 1) {
        return luaL_error(L, "'ts.cache_remove' requires parameter");
    }

    /* keystr */
    if (!lua_isstring(L, 1)) {
        return luaL_error(L, "'ts.cache_remove' first param is not string");
    }

    keystr = luaL_checklstring(L, 1, &key_len);

    optstr = NULL;
    opt_len = 0;

    /* option */
    if (n >= 2 && lua_isstring(L, 2)) {
        optstr = luaL_checklstring(L, 2, &opt_len);;
    }

    key = ts_lua_cache_key_create(keystr, key_len, optstr, opt_len);
    if (key == NULL) {
        return luaL_error(L, "'ts.cache_remove' failed");
    }

    info = (ts_lua_cache_info*)TSmalloc(sizeof(ts_lua_cache_info));
    memset(info, 0, sizeof(ts_lua_cache_info));
    info->cache_key = key;

    contp = TSContCreate(ts_lua_cache_remove_handler, ci->mutex);
    ai = ts_lua_async_create_item(contp, ts_lua_cache_cleanup, info, ci);
    TSContDataSet(contp, ai);

    action = TSCacheRemove(contp, key);

    if (!TSActionDone(action)) {
        info->cache_action = action;
        return lua_yield(L, 0);

    } else {            // action done
        ts_lua_release_cache_info(info, 1);
        ai->data = NULL;
        return 0;
    }
}
Ejemplo n.º 18
0
static int astats_origin(TSCont cont, TSEvent event, void *edata) {
	TSCont icontp;
	stats_state *my_state;
	config_t* config;
	TSHttpTxn txnp = (TSHttpTxn) edata;
	TSMBuffer reqp;
	TSMLoc hdr_loc = NULL, url_loc = NULL;
	TSEvent reenable = TS_EVENT_HTTP_CONTINUE;
	config = get_config(cont);

	TSDebug(PLUGIN_TAG, "in the read stuff");

	if (TSHttpTxnClientReqGet(txnp, &reqp, &hdr_loc) != TS_SUCCESS)
		goto cleanup;

	if (TSHttpHdrUrlGet(reqp, hdr_loc, &url_loc) != TS_SUCCESS)
		goto cleanup;

	int path_len = 0;
	const char* path = TSUrlPathGet(reqp,url_loc,&path_len);
	TSDebug(PLUGIN_TAG,"Path: %.*s",path_len,path);
	TSDebug(PLUGIN_TAG,"Path: %.*s",path_len,path);

	if (!(path_len == config->stats_path_len && !memcmp(path, config->stats_path, config->stats_path_len))) {
//		TSDebug(PLUGIN_TAG, "not right path: %.*s",path_len,path);
		goto notforme;
	}

	const struct sockaddr *addr = TSHttpTxnClientAddrGet(txnp);
	if(!is_ip_allowed(config, addr)) {
		TSDebug(PLUGIN_TAG, "not right ip");
		goto notforme;
	}
//	TSDebug(PLUGIN_TAG,"Path...: %.*s",path_len,path);

	int query_len;
	char *query = (char*)TSUrlHttpQueryGet(reqp,url_loc,&query_len);
	TSDebug(PLUGIN_TAG,"query: %.*s",query_len,query);

	TSSkipRemappingSet(txnp,1); //not strictly necessary, but speed is everything these days

	/* This is us -- register our intercept */
	TSDebug(PLUGIN_TAG, "Intercepting request");

	icontp = TSContCreate(stats_dostuff, TSMutexCreate());
	my_state = (stats_state *) TSmalloc(sizeof(*my_state));
	memset(my_state, 0, sizeof(*my_state));

	my_state->recordTypes = config->recordTypes;
	if (query_len) {
		my_state->query = nstrl(query, query_len);
		TSDebug(PLUGIN_TAG,"new query: %s", my_state->query);
		stats_fillState(my_state, my_state->query, query_len);
	}

	TSContDataSet(icontp, my_state);
	TSHttpTxnIntercept(icontp, txnp);

	goto cleanup;

	notforme:

	cleanup:
#if (TS_VERSION_NUMBER < 2001005)
	if (path)
		TSHandleStringRelease(reqp, url_loc, path);
#endif
	if (url_loc)
		TSHandleMLocRelease(reqp, hdr_loc, url_loc);
	if (hdr_loc)
		TSHandleMLocRelease(reqp, TS_NULL_MLOC, hdr_loc);

	TSHttpTxnReenable(txnp, reenable);

	return 0;
}
Ejemplo n.º 19
0
static int
ts_lua_shared_dict_set(lua_State *L)
{
    int                     n;
    int64_t                 nkey, nval;
    const char              *key, *val;
    size_t                  key_len, val_len;
    int                     ktype, vtype;
    void                    *hKey;
    int                     isNew;
    Tcl_HashEntry           *hPtr;
    ts_lua_shared_dict_item *item, *old_item;
    ts_lua_shared_dict      *dct;

    n = lua_gettop(L);

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

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

    if (dct->quota && dct->used > dct->quota) {
        lua_pushnumber(L, 0);
        lua_pushlstring(L, "no memory", sizeof("no memory") - 1);
        return 2;
    }

    ktype = lua_type(L, 2);
    vtype = lua_type(L, 3);

    switch (ktype) {

        case LUA_TNUMBER:
            if (dct->flags & TS_LUA_SHDICT_FLAG_INTKEY) {
                nkey = luaL_checknumber(L, 2);
                key_len = sizeof(long);
                hKey = (void*)nkey;

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

            break;

        case LUA_TSTRING:
            if (dct->flags & TS_LUA_SHDICT_FLAG_INTKEY) {
                return luaL_error(L, "key for xx:set() should be number");
            }

            key = luaL_checklstring(L, 2, &key_len);
            hKey = (void*)key;
            break;

        default:
            return luaL_error(L, "invalid key type: %s for xx:set()", lua_typename(L, ktype));
    }

    if (key_len > TS_LUA_SHDICT_MAX_KEY_LENGTH)
        return luaL_error(L, "key length is too long: %d", (int)key_len);

    val_len = 0;
    switch (vtype) {

        case LUA_TNUMBER:
            nval = lua_tonumber(L, 3);
            break;

        case LUA_TSTRING:
            val = lua_tolstring(L, 3, &val_len);
            break;

        case LUA_TBOOLEAN:
            nval = lua_toboolean(L, 3);
            break;

        case LUA_TNIL:
            nval = 0;
            break;

        default:
            return luaL_error(L, "invalid val type: %s for xx:set()", lua_typename(L, vtype));
    }

    if (val_len > TS_LUA_SHDICT_MAX_VAL_LENGTH)
        return luaL_error(L, "val length is too long: %d", (int)val_len);

    item = (ts_lua_shared_dict_item*)TSmalloc(sizeof(ts_lua_shared_dict_item) + val_len);
    item->vtype = vtype;
    item->ksize = key_len;
    item->vsize = val_len;

    if (vtype == LUA_TSTRING) {
        item->v.s = (char*)(((char*)item) + sizeof(ts_lua_shared_dict_item));
        memcpy(item->v.s, val, val_len);

    } else {
        item->v.n = nval;
    }

    isNew = 0;
    old_item = NULL;

    TSMutexLock(dct->map.mutexp);
    hPtr = Tcl_CreateHashEntry(&(dct->map.t), hKey, &isNew);

    if (isNew) {
        Tcl_SetHashValue(hPtr, item);
        dct->used += sizeof(ts_lua_shared_dict_item) + item->ksize + item->vsize;

    } else {
        old_item = (ts_lua_shared_dict_item*)Tcl_GetHashValue(hPtr);
        Tcl_SetHashValue(hPtr, item);
        dct->used += (int)(item->ksize + item->vsize) - (int)(old_item->ksize + old_item->vsize);
    }

    TSMutexUnlock(dct->map.mutexp);

    if (!isNew && old_item) {
        TSfree(old_item);
    }

    lua_pushnumber(L, 1);
    lua_pushnil(L);

    return 2;
}
Ejemplo n.º 20
0
static inline void *
ts_malloc(size_t s)
{
  return TSmalloc(s);
}
static CachedHeaderInfo *
get_cached_header_info(TSHttpTxn txn)
{
  CachedHeaderInfo *chi;
  TSMBuffer cr_buf;
  TSMLoc cr_hdr_loc, cr_date_loc, cr_cache_control_loc, cr_cache_control_dup_loc;
  int cr_cache_control_count, val_len, i;
  char *value, *ptr;

  chi = (CachedHeaderInfo *)TSmalloc(sizeof(CachedHeaderInfo));
  memset(chi, 0, sizeof(CachedHeaderInfo));

  if (TSHttpTxnCachedRespGet(txn, &cr_buf, &cr_hdr_loc) == TS_SUCCESS) {
    cr_date_loc = TSMimeHdrFieldFind(cr_buf, cr_hdr_loc, TS_MIME_FIELD_DATE, TS_MIME_LEN_DATE);
    if (cr_date_loc != TS_NULL_MLOC) {
      TSDebug(PLUGIN_NAME, "Found a date");
      chi->date = TSMimeHdrFieldValueDateGet(cr_buf, cr_hdr_loc, cr_date_loc);
      TSHandleMLocRelease(cr_buf, cr_hdr_loc, cr_date_loc);
    }

    cr_cache_control_loc = TSMimeHdrFieldFind(cr_buf, cr_hdr_loc, TS_MIME_FIELD_CACHE_CONTROL, TS_MIME_LEN_CACHE_CONTROL);

    while (cr_cache_control_loc != TS_NULL_MLOC) {
      TSDebug(PLUGIN_NAME, "Found cache-control");
      cr_cache_control_count = TSMimeHdrFieldValuesCount(cr_buf, cr_hdr_loc, cr_cache_control_loc);

      for (i = 0; i < cr_cache_control_count; i++) {
        value = (char *)TSMimeHdrFieldValueStringGet(cr_buf, cr_hdr_loc, cr_cache_control_loc, i, &val_len);
        ptr   = value;

        if (strncmp(value, TS_HTTP_VALUE_MAX_AGE, TS_HTTP_LEN_MAX_AGE) == 0) {
          TSDebug(PLUGIN_NAME, "Found max-age");
          ptr += TS_HTTP_LEN_MAX_AGE;
          if (*ptr == '=') {
            ptr++;
            chi->max_age = atol(ptr);
          } else {
            ptr = TSstrndup(value, TS_HTTP_LEN_MAX_AGE + 2);
            TSDebug(PLUGIN_NAME, "This is what I found: %s", ptr);
            TSfree(ptr);
          }
        } else if (strncmp(value, HTTP_VALUE_STALE_WHILE_REVALIDATE, strlen(HTTP_VALUE_STALE_WHILE_REVALIDATE)) == 0) {
          TSDebug(PLUGIN_NAME, "Found stale-while-revalidate");
          ptr += strlen(HTTP_VALUE_STALE_WHILE_REVALIDATE);
          if (*ptr == '=') {
            ptr++;
            chi->stale_while_revalidate = atol(ptr);
          }
        } else if (strncmp(value, HTTP_VALUE_STALE_IF_ERROR, strlen(HTTP_VALUE_STALE_IF_ERROR)) == 0) {
          TSDebug(PLUGIN_NAME, "Found stale-on-error");
          ptr += strlen(HTTP_VALUE_STALE_IF_ERROR);
          if (*ptr == '=') {
            ptr++;
            chi->stale_on_error = atol(ptr);
          }
        } else {
          TSDebug(PLUGIN_NAME, "Unknown field value");
        }
      }

      cr_cache_control_dup_loc = TSMimeHdrFieldNextDup(cr_buf, cr_hdr_loc, cr_cache_control_loc);
      TSHandleMLocRelease(cr_buf, cr_hdr_loc, cr_cache_control_loc);
      cr_cache_control_loc = cr_cache_control_dup_loc;
    }
    TSHandleMLocRelease(cr_buf, TS_NULL_MLOC, cr_hdr_loc);
  }

  return chi;
}
Ejemplo n.º 22
0
static char * nstr(const char *s) {
	char *mys = (char *)TSmalloc(strlen(s)+1);
	strcpy(mys, s);
	return mys;
}
Ejemplo n.º 23
0
void
TSPluginInit(int argc, const char *argv[])
{
  int ret = 0;
  ts_lua_g_main_ctx_array = TSmalloc(sizeof(ts_lua_main_ctx) * TS_LUA_MAX_STATE_COUNT);
  memset(ts_lua_g_main_ctx_array, 0, sizeof(ts_lua_main_ctx) * TS_LUA_MAX_STATE_COUNT);

  ret = ts_lua_create_vm(ts_lua_g_main_ctx_array, TS_LUA_MAX_STATE_COUNT);

  if (ret) {
    ts_lua_destroy_vm(ts_lua_g_main_ctx_array, TS_LUA_MAX_STATE_COUNT);
    TSfree(ts_lua_g_main_ctx_array);
    return;
  }

  if (argc < 2) {
    TSError("[%s] lua script file required !!", __FUNCTION__);
    return;
  }

  if (strlen(argv[1]) >= TS_LUA_MAX_SCRIPT_FNAME_LENGTH - 16) {
    TSError("[%s] lua script file name too long !!", __FUNCTION__);
    return;
  }

  ts_lua_instance_conf *conf = TSmalloc(sizeof(ts_lua_instance_conf));
  if (!conf) {
    TSError("[%s] TSmalloc failed !!", __FUNCTION__);
    return;
  }
  memset(conf, 0, sizeof(ts_lua_instance_conf));

  sprintf(conf->script, "%s", argv[1]);

  ts_lua_init_instance(conf);

  ret = ts_lua_add_module(conf, ts_lua_g_main_ctx_array, TS_LUA_MAX_STATE_COUNT, argc - 1, (char **) &argv[1]);

  if (ret != 0) {
    TSError("[%s] ts_lua_add_module failed", __FUNCTION__);
    return;
  }

  TSCont global_contp = TSContCreate(globalHookHandler, NULL);
  if (!global_contp) {
    TSError("[%s] could not create transaction start continuation", __FUNCTION__);
    return;
  }
  TSContDataSet(global_contp, conf);

  //adding hook based on whether the lua global function exists.
  ts_lua_main_ctx *main_ctx = &ts_lua_g_main_ctx_array[0];
  ts_lua_http_ctx *http_ctx = ts_lua_create_http_ctx(main_ctx, conf);
  lua_State *l = http_ctx->lua;

  lua_getglobal(l, TS_LUA_FUNCTION_G_SEND_REQUEST);
  if (lua_type(l, -1) == LUA_TFUNCTION) {
    TSHttpHookAdd(TS_HTTP_SEND_REQUEST_HDR_HOOK, global_contp);
    TSDebug(TS_LUA_DEBUG_TAG, "send_request_hdr_hook added");
  }
  lua_pop(l, 1);

  lua_getglobal(l, TS_LUA_FUNCTION_G_READ_RESPONSE);
  if (lua_type(l, -1) == LUA_TFUNCTION) {
    TSHttpHookAdd(TS_HTTP_READ_RESPONSE_HDR_HOOK, global_contp);
    TSDebug(TS_LUA_DEBUG_TAG, "read_response_hdr_hook added");
  }
  lua_pop(l, 1);

  lua_getglobal(l, TS_LUA_FUNCTION_G_SEND_RESPONSE);
  if (lua_type(l, -1) == LUA_TFUNCTION) {
    TSHttpHookAdd(TS_HTTP_SEND_RESPONSE_HDR_HOOK, global_contp);
    TSDebug(TS_LUA_DEBUG_TAG, "send_response_hdr_hook added");
  }
  lua_pop(l, 1);

  lua_getglobal(l, TS_LUA_FUNCTION_G_CACHE_LOOKUP_COMPLETE);
  if (lua_type(l, -1) == LUA_TFUNCTION) {
    TSHttpHookAdd(TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK, global_contp);
    TSDebug(TS_LUA_DEBUG_TAG, "cache_lookup_complete_hook added");
  }
  lua_pop(l, 1);

  lua_getglobal(l, TS_LUA_FUNCTION_G_READ_REQUEST);
  if (lua_type(l, -1) == LUA_TFUNCTION) {
    TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, global_contp);
    TSDebug(TS_LUA_DEBUG_TAG, "read_request_hdr_hook added");
  }
  lua_pop(l, 1);

  lua_getglobal(l, TS_LUA_FUNCTION_G_TXN_START);
  if (lua_type(l, -1) == LUA_TFUNCTION) {
    TSHttpHookAdd(TS_HTTP_TXN_START_HOOK, global_contp);
    TSDebug(TS_LUA_DEBUG_TAG, "txn_start_hook added");
  }
  lua_pop(l, 1);

  lua_getglobal(l, TS_LUA_FUNCTION_G_PRE_REMAP);
  if (lua_type(l, -1) == LUA_TFUNCTION) {
    TSHttpHookAdd(TS_HTTP_PRE_REMAP_HOOK, global_contp);
    TSDebug(TS_LUA_DEBUG_TAG, "pre_remap_hook added");
  }
  lua_pop(l, 1);

  lua_getglobal(l, TS_LUA_FUNCTION_G_POST_REMAP);
  if (lua_type(l, -1) == LUA_TFUNCTION) {
    TSHttpHookAdd(TS_HTTP_POST_REMAP_HOOK, global_contp);
    TSDebug(TS_LUA_DEBUG_TAG, "post_remap_hook added");
  }
  lua_pop(l, 1);

  lua_getglobal(l, TS_LUA_FUNCTION_G_SELECT_ALT);
  if (lua_type(l, -1) == LUA_TFUNCTION) {
    TSHttpHookAdd(TS_HTTP_SELECT_ALT_HOOK, global_contp);
    TSDebug(TS_LUA_DEBUG_TAG, "select_alt_hook added");
  }
  lua_pop(l, 1);

  lua_getglobal(l, TS_LUA_FUNCTION_G_OS_DNS);
  if (lua_type(l, -1) == LUA_TFUNCTION) {
    TSHttpHookAdd(TS_HTTP_OS_DNS_HOOK, global_contp);
    TSDebug(TS_LUA_DEBUG_TAG, "os_dns_hook added");
  }
  lua_pop(l, 1);

  lua_getglobal(l, TS_LUA_FUNCTION_G_READ_CACHE);
  if (lua_type(l, -1) == LUA_TFUNCTION) {
    TSHttpHookAdd(TS_HTTP_READ_CACHE_HDR_HOOK, global_contp);
    TSDebug(TS_LUA_DEBUG_TAG, "read_cache_hdr_hook added");
  }
  lua_pop(l, 1);

  lua_getglobal(l, TS_LUA_FUNCTION_G_TXN_CLOSE);
  if (lua_type(l, -1) == LUA_TFUNCTION) {
    TSHttpHookAdd(TS_HTTP_TXN_CLOSE_HOOK, global_contp);
    TSDebug(TS_LUA_DEBUG_TAG, "txn_close_hook added");
  }
  lua_pop(l, 1);

  ts_lua_destroy_http_ctx(http_ctx);

}
Ejemplo n.º 24
0
static void ironbee_plugin_txn_start(TSCont contp, TSHttpTxn txnp)
{
    assert(contp != NULL);
    assert(txnp != NULL);

    /* start of Request */
    /* First req on a connection, we set up conn stuff */
    ib_status_t  rc;
    ib_engine_t *ib = NULL;
    TSCont mycont;
    tsib_ssn_ctx *ssndata;
    tsib_txn_ctx *txndata;

    ssndata = TSContDataGet(contp);

    if (ssndata->iconn == NULL) {
        rc = tsib_manager_engine_acquire(&ib);
        if (rc == IB_DECLINED) {
            /* OK, this means the manager is disabled deliberately,
             * but otherwise all's well.  So this TXN
             * gets processed without intervention from Ironbee
             * and is invisble when our SSN_CLOSE hook runs.
             */
            TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
            TSDebug("ironbee", "Decline from engine manager");
            return;
        }
        else if (rc != IB_OK) {
            TSError("[ironbee] Failed to acquire engine: %s",
                    ib_status_to_string(rc));
            goto noib_error;
        }
        if (ib != NULL) {
            rc = ib_conn_create(ib, &ssndata->iconn, contp);
            if (rc != IB_OK) {
                TSError("[ironbee] ib_conn_create: %s",
                        ib_status_to_string(rc));
                tsib_manager_engine_release(ib);
                goto noib_error;
            }

            /* In the normal case, release the engine when the
             * connection's memory pool is destroyed */
            rc = ib_mm_register_cleanup(ssndata->iconn->mm,
                                        cleanup_ib_connection,
                                        ib);
            if (rc != IB_OK) {
                TSError("[ironbee] ib_mm_register_cleanup: %s",
                        ib_status_to_string(rc));
                tsib_manager_engine_release(ib);
                goto noib_error;
            }

            TSDebug("ironbee", "CONN CREATE: conn=%p", ssndata->iconn);
            ssndata->txnp = txnp;
            ssndata->txn_count = ssndata->closing = 0;

            rc = ironbee_conn_init(ssndata);
            if (rc != IB_OK) {
                TSError("[ironbee] ironbee_conn_init: %s",
                        ib_status_to_string(rc));
                goto noib_error;
            }

            TSContDataSet(contp, ssndata);
            TSDebug("ironbee",
                    "ironbee_plugin: ib_state_notify_conn_opened()");
            rc = ib_state_notify_conn_opened(ib, ssndata->iconn);
            if (rc != IB_OK) {
                TSError("[ironbee] Failed to notify connection opened: %s",
                        ib_status_to_string(rc));
            }
        }
        else {
            /* Use TSError where there's no ib or tx */
            TSError("Ironbee: No ironbee engine!");
            goto noib_error;
        }
    }

    /* create a txn cont (request ctx) and tx */
    txndata = TSmalloc(sizeof(*txndata));
    memset(txndata, 0, sizeof(*txndata));
    txndata->ssn = ssndata;
    txndata->txnp = txnp;

    rc = ib_tx_create(&txndata->tx, ssndata->iconn, txndata);
    if (rc != IB_OK) {
        TSError("[ironbee] Failed to create tx: %d", rc);
        tsib_manager_engine_release(ib);
        TSfree(txndata);
        goto noib_error;
    }

    ++ssndata->txn_count;

    ib_log_debug_tx(txndata->tx,
                    "TX CREATE: conn=%p tx=%p id=%s txn_count=%d",
                    ssndata->iconn, txndata->tx, txndata->tx->id,
                    txndata->ssn->txn_count);

    mycont = TSContCreate(ironbee_plugin, TSContMutexGet(contp));
    TSContDataSet(mycont, txndata);

    TSHttpTxnHookAdd(txnp, TS_HTTP_TXN_CLOSE_HOOK, mycont);

    /* Hook to process responses */
    TSHttpTxnHookAdd(txnp, TS_HTTP_READ_RESPONSE_HDR_HOOK, mycont);

    /* Hook to process requests */
    TSHttpTxnHookAdd(txnp, TS_HTTP_PRE_REMAP_HOOK, mycont);

    /* Hook to process request headers when sent to the server. */
    TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_REQUEST_HDR_HOOK, mycont);

    /* Create continuations for input and output filtering
     * to give them txn lifetime.
     */
    txndata->in_data_cont = TSTransformCreate(in_data_event, txnp);
    TSContDataSet(txndata->in_data_cont, txndata);

    txndata->out_data_cont = TSTransformCreate(out_data_event, txnp);
    TSContDataSet(txndata->out_data_cont, txndata);

    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
    return;

noib_error:

    /* NULL txndata signals this to SEND_RESPONSE */
    TSContDataSet(contp, NULL);

    TSError("[ironbee] Internal error initialising for transaction");
    TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp);

    /* FIXME: check this.
     * Purpose is to ensure contp doesn't leak, but may not be right
     */
    TSHttpTxnHookAdd(txnp, TS_HTTP_TXN_CLOSE_HOOK, contp);

    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR);
    return;
}
Ejemplo n.º 25
0
static bool
load_config(plugin_state_t *pstate, invalidate_t **ilist)
{
  FILE *fs;
  struct stat s;
  size_t path_len;
  char *path;
  char line[LINE_MAX];
  time_t now;
  pcre *config_re;
  const char *errptr;
  int erroffset, ovector[OVECTOR_SIZE], rc;
  int ln = 0;
  invalidate_t *iptr, *i;

  if (pstate->config_file[0] != '/') {
    path_len = strlen(TSConfigDirGet()) + strlen(pstate->config_file) + 2;
    path = alloca(path_len);
    snprintf(path, path_len, "%s/%s", TSConfigDirGet(), pstate->config_file);
  } else
    path = pstate->config_file;
  if (stat(path, &s) < 0) {
    TSDebug(LOG_PREFIX, "Could not stat %s", path);
    return false;
  }
  if (s.st_mtime > pstate->last_load) {
    now = time(NULL);
    if (!(fs = fopen(path, "r"))) {
      TSDebug(LOG_PREFIX, "Could not open %s for reading", path);
      return false;
    }
    config_re = pcre_compile("^([^#].+?)\\s+(\\d+)\\s*$", 0, &errptr, &erroffset, NULL);
    while (fgets(line, LINE_MAX, fs) != NULL) {
      ln++;
      TSDebug(LOG_PREFIX, "Processing: %d %s", ln, line);
      rc = pcre_exec(config_re, NULL, line, strlen(line), 0, 0, ovector, OVECTOR_SIZE);
      if (rc == 3) {
        i = (invalidate_t *)TSmalloc(sizeof(invalidate_t));
        init_invalidate_t(i);
        pcre_get_substring(line, ovector, rc, 1, &i->regex_text);
        i->epoch = now;
        i->expiry = atoi(line + ovector[4]);
        i->regex = pcre_compile(i->regex_text, 0, &errptr, &erroffset, NULL);
        if (i->expiry <= i->epoch) {
          TSDebug(LOG_PREFIX, "Rule is already expired!");
          free_invalidate_t(i);
        } else if (i->regex == NULL) {
          TSDebug(LOG_PREFIX, "%s did not compile", i->regex_text);
          free_invalidate_t(i);
        } else {
          i->regex_extra = pcre_study(i->regex, 0, &errptr);
          if (!*ilist) {
            *ilist = i;
            TSDebug(LOG_PREFIX, "Created new list and Loaded %s %d %d", i->regex_text, (int)i->epoch, (int)i->expiry);
          } else {
            iptr = *ilist;
            while (1) {
              if (strcmp(i->regex_text, iptr->regex_text) == 0) {
                if (iptr->expiry != i->expiry) {
                  TSDebug(LOG_PREFIX, "Updating duplicate %s", i->regex_text);
                  iptr->epoch = i->epoch;
                  iptr->expiry = i->expiry;
                }
                free_invalidate_t(i);
                i = NULL;
                break;
              } else if (!iptr->next)
                break;
              else
                iptr = iptr->next;
            }
            if (i) {
              iptr->next = i;
              TSDebug(LOG_PREFIX, "Loaded %s %d %d", i->regex_text, (int)i->epoch, (int)i->expiry);
            }
          }
        }
      } else
        TSDebug(LOG_PREFIX, "Skipping line %d", ln);
    }
    pcre_free(config_re);
    fclose(fs);
    pstate->last_load = s.st_mtime;
    return true;
  } else
    TSDebug(LOG_PREFIX, "File mod time is not newer: %d >= %d", (int)pstate->last_load, (int)s.st_mtime);
  return false;
}
Ejemplo n.º 26
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 *
hc_thread(void *data)
{
  int fd = inotify_init();
  HCDirEntry *dirs;
  int len;
  HCFileData *fl = NULL;
  char buffer[INOTIFY_BUFLEN];
  struct timeval last_free, now;

  gettimeofday(&last_free, NULL);

  /* Setup watchers for the directories, these are a one time setup */
  dirs = setup_watchers(fd);

  while (1) {
    int i = 0;

    /* First clean out anything old from the freelist */
    gettimeofday(&now, NULL);
    if ((now.tv_sec  - last_free.tv_sec) > FREELIST_TIMEOUT) {
      HCFileData *fdata = fl, *prev_fdata = fl;

      TSDebug(PLUGIN_NAME, "Checking the freelist");
      memcpy(&last_free, &now, sizeof(struct timeval));
      while(fdata) {
        if (fdata->remove > now.tv_sec) {
          if (prev_fdata)
            prev_fdata->_next = fdata->_next;
          fdata = fdata->_next;
          TSDebug(PLUGIN_NAME, "Cleaning up entry from frelist");
          TSfree(fdata);
        } else {
          prev_fdata = fdata;
          fdata = fdata->_next;
        }
      }
    }
    
    /* Read the inotify events, blocking! */
    len  = read(fd, buffer, INOTIFY_BUFLEN);
    if (len >= 0) {
      while (i < len) {
        struct inotify_event *event = (struct inotify_event *)&buffer[i];
        int wd = event->wd;
        HCFileInfo *finfo = g_config;

        while (finfo) {
          if ((wd == finfo->wd) || (wd == finfo->dir->wd && !strncmp(event->name, finfo->basename, event->len)))
            break;
          finfo = finfo->_next;
        }
        if (finfo) {
          HCFileData *new_data = TSmalloc(sizeof(HCFileData));

          if (event->mask & (IN_CLOSE_WRITE)) {
            TSDebug(PLUGIN_NAME, "Modify file event (%d) on %s", event->mask, finfo->fname);
          } else if (event->mask & (IN_CREATE|IN_MOVED_TO)) {
            TSDebug(PLUGIN_NAME, "Create file event (%d) on %s", event->mask, finfo->fname);
            finfo->wd = inotify_add_watch(fd, finfo->fname, IN_DELETE_SELF|IN_CLOSE_WRITE|IN_ATTRIB);
          } else if (event->mask & (IN_DELETE_SELF|IN_MOVED_FROM)) {
            TSDebug(PLUGIN_NAME, "Delete file event (%d) on %s", event->mask, finfo->fname);
            finfo->wd = inotify_rm_watch(fd, finfo->wd);
          }
          memset(new_data, 0, sizeof(HCFileData));
          reload_status_file(finfo, new_data);
          finfo->data->_next = fl;
          finfo->data->remove = now.tv_sec + FREELIST_TIMEOUT;
          fl = finfo->data;
          ink_atomic_swap_ptr(&(finfo->data), new_data);
        }
        i += sizeof(struct inotify_event) + event->len;
      }
    }
  }

  /* Cleanup, in case we later exit this thread ... */
  while (dirs) {
    HCDirEntry *d = dirs;

    dirs = dirs->_next;
    TSfree(d);
  }

  return NULL; /* Yeah, that never happens */
}
Ejemplo n.º 28
0
static int
ts_lua_cache_open(lua_State *L)
{
    const char              *keystr, *optstr;
    size_t                  key_len, opt_len;
    int                     operate, n;
    TSCont                  contp;
    TSCacheKey              key;
    TSAction                action;
    ts_lua_cont_info        *ci;
    ts_lua_async_item       *ai;
    ts_lua_cache_info       *info;

    ci = ts_lua_get_cont_info(L);
    if (ci == NULL)
        return 0;

    n = lua_gettop(L);
    if (n < 2) {
        return luaL_error(L, "'ts.cache_open' requires parameter");
    }

    /* keystr */
    if (!lua_isstring(L, 1)) {
        return luaL_error(L, "'ts.cache_open' first param is not string");

    } else if (!lua_isnumber(L, 2)) {
        return luaL_error(L, "'ts.cache_open' second param is not TS_LUA_CACHE_READ/TS_LUA_CACHE_WRITE");
    }

    keystr = luaL_checklstring(L, 1, &key_len);
    operate = lua_tonumber(L, 2);

    if (operate != TS_LUA_CACHE_READ && operate != TS_LUA_CACHE_WRITE) {
        return luaL_error(L, "'ts.cache_open' second param is not TS_LUA_CACHE_READ/TS_LUA_CACHE_WRITE");
    }

    optstr = NULL;
    opt_len = 0;

    /* option */
    if (n >= 3 && lua_isstring(L, 3)) {
        optstr = luaL_checklstring(L, 3, &opt_len);
    }

    key = ts_lua_cache_key_create(keystr, key_len, optstr, opt_len);
    if (key == NULL) {
        return luaL_error(L, "'ts.cache_open' failed");
    }

    info = (ts_lua_cache_info*)TSmalloc(sizeof(ts_lua_cache_info));
    memset(info, 0, sizeof(ts_lua_cache_info));

    info->cache_key = key;
    info->optype = operate;  

    contp = TSContCreate(ts_lua_cache_main_handler, ci->mutex);
    ai = ts_lua_async_create_item(contp, ts_lua_cache_cleanup, info, ci);

    TSContDataSet(contp, ai);

    info->contp = contp;
    info->ioh.buffer = TSIOBufferCreate();
    info->ioh.reader = TSIOBufferReaderAlloc(info->ioh.buffer);

    if (operate == TS_LUA_CACHE_READ) {
        info->reserved.buffer = TSIOBufferCreate();
        info->reserved.reader = TSIOBufferReaderAlloc(info->reserved.buffer);
        info->current_handler = &ts_lua_cache_open_read;

        action = TSCacheRead(contp, key);

    } else {
        info->current_handler = &ts_lua_cache_open_write;
        action = TSCacheWrite(contp, key);
    }

    if (TSActionDone(action)) {     // done
        return 1;

    } else {                        // undone
        info->cache_action = action;
        return lua_yield(L, 0);
    }
}
static HCFileInfo*
parse_configs(const char* fname)
{
  FILE *fd;
  char buf[64*1024]; /* Way huge, but wth */
  HCFileInfo *head_finfo = NULL, *finfo = NULL, *prev_finfo = NULL;

  if (NULL == (fd = fopen(fname, "r")))
    return NULL;

  while (!feof(fd)) {
    char *str, *save;
    int state = 0;
    char *ok=NULL, *miss=NULL, *mime=NULL;

    prev_finfo = finfo;
    finfo = TSmalloc(sizeof(HCFileInfo));
    memset(finfo, 0, sizeof(HCFileInfo));

    if (NULL == head_finfo)
      head_finfo = finfo;
    if (prev_finfo)
      prev_finfo->_next = finfo;

    fread(buf, sizeof(buf), 1, fd);
    str = strtok_r(buf, "\t", &save);
    while (NULL != str) {
      if (strlen(str) > 0) {
        switch (state) {
        case 0:
          if ('/' == *str)
            ++str;
          strncpy(finfo->path, str, MAX_PATH_LEN - 1);
          finfo->p_len = strlen(finfo->path);
          break;
        case 1:
          strncpy(finfo->fname, str, MAX_FILENAME_LEN - 1);
          finfo->basename = strrchr(finfo->fname, '/');
          if (finfo->basename)
            ++(finfo->basename);
          break;
        case 2:
          mime = str;
          break;
        case 3:
          ok = str;
          break;
        case 4:
          miss = str;
          break;
        }
        ++state;
      }
      str = strtok_r(NULL, "\t", &save);
    }

    finfo->ok = gen_header(ok, mime, &finfo->o_len);
    finfo->miss = gen_header(miss, mime, &finfo->m_len);
    finfo->data = TSmalloc(sizeof(HCFileData));
    memset(finfo->data, 0, sizeof(HCFileData));
    reload_status_file(finfo, finfo->data);
  }
  fclose(fd);

  return head_finfo;
}
Ejemplo n.º 30
0
static int
ts_lua_cache_read(lua_State *L)
{
    int64_t                 length, n, avail;
    char                    *dst;
    ts_lua_cont_info        *ci;
    ts_lua_cache_info       *info;

    ci = ts_lua_get_cont_info(L);
    if (ci == NULL)
        return 0;

    n = lua_gettop(L);
    if (n < 1) {
        return luaL_error(L, "'ts.cache_read' requires parameter");
    }

    /* length */
    if (n >= 2) {
        if (!lua_isnumber(L, 2)) {
            return luaL_error(L, "'ts.cache_read' second param is not number");
        }

        length = lua_tonumber(L, 2);
        if (length <= 0) {
            return luaL_error(L, "'ts.cache_read' second param is a not valid number");
        }

    } else {
        length = INT64_MAX;
    }

    /* table */
    if (!lua_istable(L, 1)) {
        return luaL_error(L, "'ts.cache_read' first param is not valid");
    }

    lua_pushlstring(L, "info", sizeof("info") - 1);
    lua_gettable(L, 1);

    if (!lua_islightuserdata(L, -1)) {
        return luaL_error(L, "'ts.cache_read' first param is not valid");
    }

    info = (ts_lua_cache_info*)lua_touserdata(L, -1);
    lua_pop(L, 1);

    if (info->hit == 0) {
        return luaL_error(L, "'ts.cache_read' is reading from unhit doc");
    }

    if (info->optype != TS_LUA_CACHE_READ) {
        return luaL_error(L, "'ts.cache_read' is reading from invalid vc");
    }

    if (info->eof || info->err) {
        lua_pushnil(L);
        return 1;
    }

    if (length != INT64_MAX) {
        info->need += length;

    } else {
        info->need = INT64_MAX;
    }

    info->current_handler = &ts_lua_cache_handle_read;

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

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

        info->already = info->need;
        TSIOBufferReaderConsume(info->reserved.reader, n);
        return 1;
    }

    if (info->ioh.vio == NULL) {
        info->ioh.vio = TSVConnRead(info->cache_vc, info->contp, info->ioh.buffer, INT64_MAX);

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

    info->wait = 1;
    return lua_yield(L, 0);
}