static int
transform_plugin(TSCont contp, TSEvent event, void *edata)
{
  TSHttpTxn txnp = (TSHttpTxn) edata;

  switch (event) {
  case TS_EVENT_HTTP_READ_REQUEST_HDR:
    if (request_ok(txnp)) {
      TSHttpTxnHookAdd(txnp, TS_HTTP_READ_CACHE_HDR_HOOK, contp);
      TSHttpTxnHookAdd(txnp, TS_HTTP_READ_RESPONSE_HDR_HOOK, contp);
    }
    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
    break;
  case TS_EVENT_HTTP_READ_CACHE_HDR:
    if (cache_response_ok(txnp)) {
      TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK, transform_create(txnp));
    }
    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
    break;
  case TS_EVENT_HTTP_READ_RESPONSE_HDR:
    if (server_response_ok(txnp)) {
      TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK, transform_create(txnp));
    }
    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
    break;
  default:
    break;
  }
  return 0;
}
static int
server_push_plugin(TSCont contp, TSEvent event, void *edata)
{
  TSHttpSsn ssnp;
  TSHttpTxn txnp;

  switch (event) {
  case TS_EVENT_HTTP_SSN_START:
    ssnp = (TSHttpSsn)edata;
    TSHttpSsnHookAdd(ssnp, TS_HTTP_TXN_START_HOOK, contp);
    TSHttpSsnReenable(ssnp, TS_EVENT_HTTP_CONTINUE);
    break;
  case TS_EVENT_HTTP_TXN_START:
    txnp = (TSHttpTxn)edata;
    TSHttpTxnHookAdd(txnp, TS_HTTP_READ_REQUEST_HDR_HOOK, contp);
    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
    break;
  case TS_EVENT_HTTP_READ_REQUEST_HDR:
    txnp = (TSHttpTxn)edata;
    if (should_push(txnp)) {
      TSHttpTxnServerPush(txnp, url, strlen(url));
    }
    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
    break;
  default:
    break;
  }

  return 0;
}
Exemple #3
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;
}
static void
client_add(TSHttpTxn txnp)
{
  // We use @c TSTransformCreate because ATS sees this the same as a transform, but with only
  // the input side hooked up and not the output side. Data flows from ATS in to the reader
  // but not back out to ATS. From the plugin point of view the input data is provided exactly
  // as it is with a transform.
  TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_CLIENT_HOOK, TSTransformCreate(client_reader, txnp));
}
static void
transform_add(TSHttpTxn txnp)
{
  TSVConn connp;

  TSDebug("null-transform", "Entering transform_add()");
  connp = TSTransformCreate(null_transform, txnp);
  TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK, connp);
}
static void
transform_add(TSHttpTxn txnp)
{
  TSVConn connp;

  connp = TSTransformCreate(bnull_transform, txnp);
  TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK, connp);
  return;
}
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);
}
Exemple #8
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;
}
Exemple #9
0
/*-------------------------------------------------------------------------
  transform_add
  Create a transformation and alloc data structure

  Input:
    txnp      current transaction
  Output :
  Return Value:
    1  if transformation created
    0  if not
  -------------------------------------------------------------------------*/
static int
transform_add(TSHttpTxn txnp)
{
  TSCont contp;
  ContData *data;

  contp = TSTransformCreate(transform_handler, txnp);
  data = cont_data_alloc();
  TSContDataSet(contp, data);

  TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK, contp);
  return 1;
}
Exemple #10
0
int
ts_chunked_transform(TSHttpTxn txnp)
{
    TSVConn                     connp;
    ts_chunked_transform_ctx    *ctx;

    ctx = (ts_chunked_transform_ctx*)TSmalloc(sizeof(ts_chunked_transform_ctx));
    memset(ctx, 0, sizeof(ts_chunked_transform_ctx));

    connp = TSTransformCreate(ts_chunked_transform_entry, txnp);
    TSContDataSet(connp, ctx);
    TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK, connp);
    return 0;
}
static int 
regex_match(TSCont contp, TSHttpTxn txnp)
{
	static char 	*url;
	TSMBuffer       bufp;
	TSMLoc          hdr_loc, url_loc;
	int 		url_length;
	regex_t 	*re;
	int  		ovector[30], res;

	if (TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
                TSError("couldn't retrieve client response header\n");
                goto done;
        }

        if (TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc) != TS_SUCCESS) {
                TSError("couldn't retrieve request url\n");
                TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
                goto done;
        }

        url = TSUrlStringGet(bufp, url_loc, &url_length);
        if (url == NULL) {
                TSError("couldn't get url");
                goto done;
        }

	for (re = reg; re; re = re->next) {
		res = pcre_exec(re->re, NULL, url, strlen(url), 0, 0, ovector, 30);
		if (res <= 0) {
			goto done;
		} 
		break;
	}
	
	TSContDataSet(contp, re->hdr);
	TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp);

done:
        TSfree(url);
        TSHandleMLocRelease(bufp, hdr_loc, url_loc);
        TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
	TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
	return 0;
}
Exemple #12
0
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("[blacklist-0] Couldn't retrieve client request header");
    goto done;
  }

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

  host = TSUrlHostGet(bufp, url_loc, &host_length);
  if (!host) {
    TSError("[blacklist-0] Couldn't retrieve request hostname");
    TSHandleMLocRelease(bufp, hdr_loc, url_loc);
    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
    goto done;
  }
  for (i = 0; i < nsites; i++) {
    if (strncmp(host, sites[i], host_length) == 0) {
      printf("blacklisting site: %s\n", sites[i]);
      TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp);
      TSHandleMLocRelease(bufp, hdr_loc, url_loc);
      TSHandleMLocRelease(bufp, TS_NULL_MLOC, url_loc);
      TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR);
      return;
    }
  }
  TSHandleMLocRelease(bufp, hdr_loc, url_loc);
  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);

done:
  TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
}
static int
global_plugin(TSCont contp ATS_UNUSED, TSEvent event, void *edata)
{
  TSDebug(PLUGIN_NAME, "transform_plugin starting");
  TSHttpTxn txnp = (TSHttpTxn)edata;

  switch (event) {
  case TS_EVENT_HTTP_READ_REQUEST_HDR:
    if (is_post_request(txnp)) {
      TSHttpTxnConfigIntSet(txnp, TS_CONFIG_HTTP_REQUEST_BUFFER_ENABLED, 1);
      TSHttpTxnHookAdd(txnp, TS_HTTP_REQUEST_BUFFER_READ_COMPLETE_HOOK, TSContCreate(request_buffer_plugin, TSMutexCreate()));
    }
    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
    return 0;
  default:
    break;
  }

  return 0;
}
Exemple #14
0
static void ironbee_plugin_read_request_hdr(TSCont contp, TSHttpTxn txnp)
{
    assert(contp != NULL);
    assert(txnp != NULL);

    tsib_txn_ctx *txndata;

    /* We got here from the same cont used for ssnstart.
     * If it's NULL we have a noib_error or just uninitialised IronBee
     * so we need to kill off the request as an internal error
     */
    txndata = TSContDataGet(contp);
    if (txndata == NULL) {
        TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp);
        TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR);
    }

    else {
        /* All's well */
        TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
    }
}
Exemple #15
0
static void ironbee_plugin_send_request_hdr(TSCont contp, TSHttpTxn txnp)
{
    assert(contp != NULL);
    assert(txnp != NULL);

    tsib_txn_ctx *txndata;

    txndata = TSContDataGet(contp);

    /* This event is about as late as we can possibly block
     * body attacks against the server.
     */

    /* If we are not yet blocked, ask IronBee if we should block. */
    if (!HTTP_CODE(txndata->status)) {
        if (!ib_flags_all(txndata->tx->flags, IB_TX_FREQ_FINISHED)) {
            ib_log_debug_tx(
                txndata->tx,
                "data_event: calling ib_state_notify_request_finished()"
            );
            (tsib_direction_client_req.ib_notify_end)(txndata->tx->ib, txndata->tx);
        }

        /* We we've transitioned to blocking,
         * - Add a handler for response header.
         * - Reenable with an error.
         * - Return (so we don't double-reenable).
         */
        if (HTTP_CODE(txndata->status)) {
            TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp);
            TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR);
            return;
        }
    }

    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
}
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_cont_info *ci;

    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->rri      = NULL;
    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) {
        ts_lua_destroy_http_ctx(http_ctx);
        TSMutexUnlock(main_ctx->mutexp);

        TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
        return 0;
    }

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

    ci        = &http_ctx->cinfo;
    ci->contp = txn_contp;
    ci->mutex = TSContMutexGet((TSCont)txnp);

    l = ci->routine.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:
        // client response can be changed within a transaction
        // (e.g. due to the follow redirect feature). So, clearing the pointers
        // to allow API(s) to fetch the pointers again when it re-enters the hook
        if (http_ctx->client_response_hdrp != NULL) {
            TSHandleMLocRelease(http_ctx->client_response_bufp, TS_NULL_MLOC, http_ctx->client_response_hdrp);
            http_ctx->client_response_hdrp = NULL;
        }
        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:
        ts_lua_destroy_http_ctx(http_ctx);
        TSMutexUnlock(main_ctx->mutexp);
        TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
        return 0;
    }

    if (lua_type(l, -1) != LUA_TFUNCTION) {
        lua_pop(l, 1);
        ts_lua_destroy_http_ctx(http_ctx);
        TSMutexUnlock(main_ctx->mutexp);

        TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
        return 0;
    }

    ts_lua_set_cont_info(l, NULL);

    if (lua_pcall(l, 0, 1, 0) != 0) {
        TSError("[ts_lua] 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);
    }

    TSMutexUnlock(main_ctx->mutexp);

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

    return 0;
}
Exemple #17
0
static void
handle_purge(TSHttpTxn txnp, PurgeInstance *purge)
{
  TSMBuffer reqp;
  TSMLoc hdr_loc = NULL, url_loc = NULL;
  bool should_purge = false;

  if (TS_SUCCESS == TSHttpTxnClientReqGet(txnp, &reqp, &hdr_loc)) {
    int method_len     = 0;
    const char *method = TSHttpHdrMethodGet(reqp, hdr_loc, &method_len);

    if ((TS_HTTP_METHOD_PURGE == method) || ((TS_HTTP_METHOD_GET == method) && purge->allow_get)) {
      /* First see if we require the "secret" to be passed in a header, and then use that */
      if (purge->header) {
        TSMLoc field_loc = TSMimeHdrFieldFind(reqp, hdr_loc, purge->header, purge->header_len);

        if (field_loc) {
          const char *header;
          int header_len;

          header = TSMimeHdrFieldValueStringGet(reqp, hdr_loc, field_loc, -1, &header_len);
          TSDebug(PLUGIN_NAME, "Checking for %.*s == %s ?", header_len, header, purge->secret);
          if (header && (header_len == purge->secret_len) && !memcmp(header, purge->secret, header_len)) {
            should_purge = true;
          }
          TSHandleMLocRelease(reqp, hdr_loc, field_loc);
        }
      } else {
        /* We are matching on the path component instead of a header */
        if (TS_SUCCESS == TSHttpHdrUrlGet(reqp, hdr_loc, &url_loc)) {
          int path_len     = 0;
          const char *path = TSUrlPathGet(reqp, url_loc, &path_len);

          TSDebug(PLUGIN_NAME, "Checking PATH = %.*s", path_len, path);
          if (path && (path_len >= purge->secret_len)) {
            int s_path = path_len - 1;

            while ((s_path >= 0) && ('/' != path[s_path])) { /* No memrchr in OSX */
              --s_path;
            }

            if (!memcmp(s_path > 0 ? path + s_path + 1 : path, purge->secret, purge->secret_len)) {
              should_purge = true;
            }
          }
          TSHandleMLocRelease(reqp, hdr_loc, url_loc);
        }
      }
    }
    TSHandleMLocRelease(reqp, TS_NULL_MLOC, hdr_loc);
  }

  /* Setup the continuation to handle this request if appropriate, if not, set the GenID if needed */
  if (should_purge) {
    TSCont cont = TSContCreate(purge_cont, TSMutexCreate());

    TSContDataSet(cont, purge);
    TSHttpTxnHookAdd(txnp, TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK, cont);
    TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, cont);
  } else if (purge->gen_id > 0) {
    TSHttpTxnConfigIntSet(txnp, TS_CONFIG_HTTP_CACHE_GENERATION, purge->gen_id);
  }
}
Exemple #18
0
/**
 * Plugin for the IronBee ATS.
 *
 * Handles some ATS events.
 *
 * @param[in,out] contp Pointer to the continuation
 * @param[in,out] event Event from ATS
 * @param[in,out] edata Event data
 *
 * @returns status
 */
int ironbee_plugin(TSCont contp, TSEvent event, void *edata)
{
    ib_status_t rc;
    TSCont mycont;
    TSHttpTxn txnp = (TSHttpTxn) edata;
    TSHttpSsn ssnp = (TSHttpSsn) edata;
    tsib_txn_ctx *txndata;
    tsib_ssn_ctx *ssndata;
    tsib_hdr_outcome status;
    TSMutex ts_mutex = NULL;

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

        /* CONNECTION */
        case TS_EVENT_HTTP_SSN_START:
            /* start of connection */
            /* But we can't initialize 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
             */
            ts_mutex = TSMutexCreate();
            mycont = TSContCreate(ironbee_plugin, ts_mutex);
            TSHttpSsnHookAdd (ssnp, TS_HTTP_TXN_START_HOOK, mycont);
            ssndata = TSmalloc(sizeof(*ssndata));
            memset(ssndata, 0, sizeof(*ssndata));
            /* The only failure here is EALLOC, and if that happens
             * we're ****ed anyway
             */
            rc = ib_lock_create_malloc(&(ssndata->mutex));
            assert(rc == IB_OK);
            ssndata->contp = mycont;
            ssndata->ts_mutex = ts_mutex;
            TSContDataSet(mycont, ssndata);

            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 */
            ib_status_t  rc;
            ib_engine_t *ib = NULL;

            ssndata = TSContDataGet(contp);
            ib_lock_lock(ssndata->mutex);

            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.
                     */
                    ib_lock_unlock(ssndata->mutex);
                    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
                    TSDebug("ironbee", "Decline from engine manager");
                    break;
                }
                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_lock_unlock(ssndata->mutex);

            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, ssndata->ts_mutex);
            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_READ_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);
            break;

noib_error:
            ib_lock_unlock(ssndata->mutex);

            /* NULL txndata signals this to SEND_RESPONSE */
            mycont = TSContCreate(ironbee_plugin, ssndata->ts_mutex);
            TSContDataSet(mycont, NULL);

            TSError("[ironbee] Internal error initialising for transaction");
            TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, mycont);
            TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR);
            break;
        }

        /* HTTP RESPONSE */
        case TS_EVENT_HTTP_READ_RESPONSE_HDR:
            txndata = TSContDataGet(contp);
            if (txndata->tx == NULL) {
                TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
                break;
            }

            /* Feed ironbee the headers if not done already. */
            if (!ib_flags_all(txndata->tx->flags, IB_TX_FRES_STARTED)) {
                status = process_hdr(txndata, txnp, &tsib_direction_server_resp);

                /* OK, if this was an HTTP 100 response, it's not the
                 * response we're interested in.  No headers have been
                 * sent yet, and no data will be sent until we've
                 * reached here again with the final response.
                 */
                if (status == HDR_HTTP_100) {
                    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
                    break;
                }
                // FIXME: Need to know if this fails as it (I think) means
                //        that the response did not come from the server and
                //        that ironbee should ignore it.
                /* I've not seen a fail here.  AFAICT if either the origin
                 * isn't responding or we're responding from cache. we
                 * never reach here in the first place.
                 */
            }

            /* If ironbee signalled an error while processing request body data,
             * this is the first opportunity to divert to an errordoc
             */
            if (HTTP_CODE(txndata->status)) {
                ib_log_debug_tx(txndata->tx,
                                "HTTP code %d contp=%p", txndata->status, contp);
                TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp);
                TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR);
                break;
            }

            /* If we're not going to inspect response body data 
             * we can bring forward notification of response-end
             * so we're in time to respond with an errordoc if Ironbee
             * wants to block in the response phase.
             *
             * This currently fails.  However, that appears to be because I
             * can't unset IB_TX_FINSPECT_RESBODY with InspectionEngineOptions
             */
            if (!ib_flags_all(txndata->tx->flags, IB_TX_FINSPECT_RESBODY)) {
                if (!ib_flags_all(txndata->tx->flags, IB_TX_FRES_STARTED) ) {
                    ib_state_notify_response_started(txndata->tx->ib, txndata->tx, NULL);
                }
                if (!ib_flags_all(txndata->tx->flags, IB_TX_FRES_FINISHED) ) {
                    ib_state_notify_response_finished(txndata->tx->ib, txndata->tx);
                }
                /* Test again for Ironbee telling us to block */
                if (HTTP_CODE(txndata->status)) {
                    TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp);
                    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR);
                    break;
                }
            }

            /* Flag that we're too late to divert to an error response */
            ib_tx_flags_set(txndata->tx, IB_TX_FCLIENTRES_STARTED);

            /* Normal execution.  Add output filter to inspect response. */
            TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK,
                             txndata->out_data_cont);
            TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);

            break;

        /* Hook for processing response headers. */
        case TS_EVENT_HTTP_SEND_RESPONSE_HDR:
            txndata = TSContDataGet(contp);
            if (txndata == NULL) {
                /* Ironbee is unavailable to help with our response. */
                internal_error_response(txnp);
                /* This contp isn't going through the normal flow. */
                TSContDestroy(contp);
                TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
                break;
            }

            /* If ironbee has sent us into an error response then
             * we came here in our error path, with nonzero status.
             */
            if (txndata->status != 0) {
                error_response(txnp, txndata);
            }

            /* Feed ironbee the headers if not done already. */
            if (!ib_flags_all(txndata->tx->flags, IB_TX_FRES_STARTED)) {
                if (process_hdr(txndata, txnp, &tsib_direction_client_resp) != HDR_OK) {
                    /* I think this is a shouldn't happen event, and that
                     * if it does we have an ironbee bug or misconfiguration.
                     * Log an error to catch if it happens in practice.
                     */
                    ib_log_error_tx(txndata->tx, "process_hdr returned error in send_response_hdr event");
                }
            }

            /* If there is an ironbee-generated response body, notify ironbee.
             *
             * NOTE: I do not see anywhere else to put this as the error body is
             *       just a buffer and not delivered via normal IO channels, so
             *       the error body will never get caught by an event.
             */
            if ((txndata->status != 0) && (txndata->err_body != NULL)) {
                const char *data = txndata->err_body;
                size_t data_length = txndata->err_body_len;
                ib_log_debug_tx(txndata->tx,
                        "error_response: calling ib_state_notify_response_body_data() %s:%d",
                        __FILE__, __LINE__);
                ib_state_notify_response_body_data(txndata->tx->ib,
                                                   txndata->tx,
                                                   data, data_length);
            }

            TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
            break;

        /* HTTP REQUEST */
        case TS_EVENT_HTTP_READ_REQUEST_HDR:
            /* hook to examine output headers.  They're not available yet */
            TSHttpTxnHookAdd(txnp, TS_HTTP_PRE_REMAP_HOOK, contp);

            TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
            break;

        /* hook for processing incoming request/headers
         * The OS_DNS hook is an alternative here.
         */
        case TS_EVENT_HTTP_PRE_REMAP:
        {
            int request_inspection_finished = 0;
            txndata = TSContDataGet(contp);
            assert ((txndata != NULL) && (txndata->tx != NULL));
            status = process_hdr(txndata, txnp, &tsib_direction_client_req);
            if (HDR_OUTCOME_IS_HTTP_OR_ERROR(status, txndata)) {
                if (status == HDR_HTTP_STATUS) {
                    ib_log_debug_tx(txndata->tx,
                                    "HTTP code %d contp=%p", txndata->status, contp);
                 }
                 else {
                    /* Ironbee set a status we don't handle.
                     * We returned EINVAL, but we also need housekeeping to
                     * avoid a crash in modhtp and log something bad.
                     */
                    ib_log_debug_tx(txndata->tx,
                                    "Internal error %d contp=%p", txndata->status, contp);
                    /* Ugly hack: notifications to stop modhtp bombing out */
                    request_inspection_finished = 1;
                }
            }
            else {
                /* Other nonzero statuses not supported */
                switch(status) {
                  case HDR_OK:
                    /* If we're not inspecting the Request body,
                     * we can bring forward notification of end-request
                     * so any header-only tests run on Request phase
                     * can abort the tx before opening a backend connection.
                     */
                    if (!ib_flags_all(txndata->tx->flags, IB_TX_FINSPECT_REQBODY)) {
                        request_inspection_finished = 1;
                    }
                    break;	/* All's well */
                  case HDR_HTTP_STATUS:
                    // FIXME: should we take the initiative here and return 500?
                    ib_log_error_tx(txndata->tx,
                                    "Internal error: ts-ironbee requested error but no error response set.");
                    break;
                  case HDR_HTTP_100:
                    /* This can't actually happen with current Trafficserver
                     * versions, as TS will generate a 400 error without
                     * reference to us.  But in case that changes in future ...
                     */
                    ib_log_error_tx(txndata->tx,
                                    "No request headers found.");
                    break;
                  default:
                    ib_log_error_tx(txndata->tx,
                                    "Unhandled state arose in handling request headers.");
                    break;
                }
            }
            if (request_inspection_finished) {
                if (!ib_flags_all(txndata->tx->flags, IB_TX_FREQ_STARTED) ) {
                    ib_state_notify_request_started(txndata->tx->ib, txndata->tx, NULL);
                }
                if (!ib_flags_all(txndata->tx->flags, IB_TX_FREQ_FINISHED) ) {
                    ib_state_notify_request_finished(txndata->tx->ib, txndata->tx);
                }
            }
            else {
                /* hook an input filter to watch data */
                TSHttpTxnHookAdd(txnp, TS_HTTP_REQUEST_TRANSFORM_HOOK,
                                 txndata->in_data_cont);
            }
            /* Flag that we can no longer prevent a request going to backend */
            ib_tx_flags_set(txndata->tx, IB_TX_FSERVERREQ_STARTED);

            /* Check whether Ironbee told us to block the request.
             * This could now come not just from process_hdr, but also
             * from a brought-forward notification if we aren't inspecting
             * a request body and notified request_finished.
             */
            if (HTTP_CODE(txndata->status)) {
                TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp);
                TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR);
            }
            else {
                TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
            }
            break;
        }


        /* CLEANUP EVENTS */
        case TS_EVENT_HTTP_TXN_CLOSE:
        {
            txndata = TSContDataGet(contp);

            TSContDestroy(txndata->out_data_cont);
            TSContDestroy(txndata->in_data_cont);
            TSContDataSet(contp, NULL);
            TSContDestroy(contp);
            if ( (txndata != NULL) && (txndata->tx != NULL) ) {
                ib_log_debug_tx(txndata->tx,
                                "TXN Close: %p", (void *)contp);
                tsib_txn_ctx_destroy(txndata);
            }
            TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
            break;
        }

        case TS_EVENT_HTTP_SSN_CLOSE:
            TSDebug("ironbee", "SSN Close: %p", (void *)contp);
            tsib_ssn_ctx_destroy(TSContDataGet(contp));
            tsib_manager_engine_cleanup();
            TSHttpSsnReenable(ssnp, TS_EVENT_HTTP_CONTINUE);
            break;

        case TS_EVENT_MGMT_UPDATE:
        {
            TSDebug("ironbee", "Management update");
            ib_status_t  rc;
            rc = tsib_manager_engine_create();
            if (rc != IB_OK) {
                TSError("[ironbee] Error creating new engine: %s",
                        ib_status_to_string(rc));
            }
            break;
        }

        /* if we get here we've got a bug */
        default:
            TSError("[ironbee] *** Unhandled event %d in ironbee_plugin.", event);
            break;
    }

    return 0;
}
Exemple #19
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;
}
Exemple #20
0
static void
handle_client_lookup(TSHttpTxn txnp, TSCont contp)
{
  TSMBuffer bufp;
  TSMLoc hdr_loc, url_loc;
  int host_length;

  in_addr_t clientip = 0;

  const char *host;

  /*
   * Here we declare local coupled statistics variables:
   */
  INKCoupledStat local_request_outcomes;
  INKStat local_requests_all;
  INKStat local_requests_redirects;
  INKStat local_requests_unchanged;

  /*
   *  Create local copy of the global coupled stat category:
   */
  local_request_outcomes = INKStatCoupledLocalCopyCreate("local_request_outcomes", request_outcomes);


  /*
   * Create the local copies of the global coupled stats:
   */
  local_requests_all = INKStatCoupledLocalAdd(local_request_outcomes, "requests.all.local", INKSTAT_TYPE_FLOAT);
  local_requests_redirects = INKStatCoupledLocalAdd(local_request_outcomes,
                                                    "requests.redirects.local", INKSTAT_TYPE_INT64);
  local_requests_unchanged = INKStatCoupledLocalAdd(local_request_outcomes,
                                                    "requests.unchanged.local", INKSTAT_TYPE_INT64);


  /*
   *   Increment the count of total requests:
   *     (it is more natural to treat the number of requests as an
   *      integer, but we declare this a FLOAT in order to demonstrate
   *      how to increment coupled FLOAT stats)
   */
  INKStatFloatAddTo(local_requests_all, 1.0);

  if (TSIsDebugTagSet("redirect")) {
    struct sockaddr const* addr = TSHttpTxnClientAddrGet(txnp);

    if (addr) {
      socklen_t addr_size = 0;

      if (addr->sa_family == AF_INET)
        addr_size = sizeof(struct sockaddr_in);
      else if (addr->sa_family == AF_INET6)
        addr_size = sizeof(struct sockaddr_in6);
      if (addr_size > 0) {
        char clientstring[INET6_ADDRSTRLEN];

        if (NULL != inet_ntop(addr->sa_family, addr, clientstring, addr_size))
          TSDebug("redirect", "clientip is %s and block_ip is %s", clientstring, block_ip);
      }
    }
  }

  if (TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
    TSError("couldn't retrieve client request header\n");
    goto done;
  }

  if (TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc) != TS_SUCCESS) {
    TSError("couldn't retrieve request url\n");
    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
    goto done;
  }

  host = TSUrlHostGet(bufp, url_loc, &host_length);
  if (!host) {
    TSError("couldn't retrieve request hostname\n");
    TSHandleMLocRelease(bufp, hdr_loc, url_loc);
    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
    goto done;
  }

  /*
   *   Check to see if the client is already headed to the redirect site.
   */
  if (strncmp(host, url_redirect, host_length) == 0) {
    TSHandleMLocRelease(bufp, hdr_loc, url_loc);
    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
    goto done;
  }

  /* TODO: This is odd, clientip is never set ... */
  if (ip_deny == clientip) {
    TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp);

    update_redirected_method_stats(bufp, hdr_loc);

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

    /*
     *   Increment the local redirect stat and do global update:
     */
    INKStatIncrement(local_requests_redirects);
    INKStatsCoupledUpdate(local_request_outcomes);
    INKStatCoupledLocalCopyDestroy(local_request_outcomes);

    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR);
    return;
  }

done:
  /*
   * Increment the local number unchanged stat and do global update:
   */
  INKStatIncrement(local_requests_unchanged);
  INKStatsCoupledUpdate(local_request_outcomes);
  INKStatCoupledLocalCopyDestroy(local_request_outcomes);

  TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
}
Exemple #21
0
static void ironbee_plugin_pre_remap(TSCont contp, TSHttpTxn txnp)
{
    assert(contp != NULL);
    assert(txnp != NULL);

    tsib_txn_ctx *txndata;
    tsib_hdr_outcome status;

    int request_inspection_finished = 0;
    txndata = TSContDataGet(contp);
    assert ((txndata != NULL) && (txndata->tx != NULL));
    status = process_hdr(txndata, txnp, &tsib_direction_client_req);
    if (HDR_OUTCOME_IS_HTTP_OR_ERROR(status, txndata)) {
        if (status == HDR_HTTP_STATUS) {
            ib_log_debug_tx(txndata->tx,
                            "HTTP code %d contp=%p", txndata->status, contp);
         }
         else {
            /* Ironbee set a status we don't handle.
             * We returned EINVAL, but we also need housekeeping to
             * avoid a crash in modhtp and log something bad.
             */
            ib_log_debug_tx(txndata->tx,
                            "Internal error %d contp=%p", txndata->status, contp);
            /* Ugly hack: notifications to stop modhtp bombing out */
            request_inspection_finished = 1;
        }
    }
    else {
        /* Other nonzero statuses not supported */
        switch(status) {
          case HDR_OK:
            /* If we're not inspecting the Request body,
             * we can bring forward notification of end-request
             * so any header-only tests run on Request phase
             * can abort the tx before opening a backend connection.
             */
            if (!ib_flags_all(txndata->tx->flags, IB_TX_FINSPECT_REQBODY)) {
                request_inspection_finished = 1;
            }
            break;	/* All's well */
          case HDR_HTTP_STATUS:
            // FIXME: should we take the initiative here and return 500?
            ib_log_error_tx(txndata->tx,
                            "Internal error: ts-ironbee requested error but no error response set.");
            break;
          case HDR_HTTP_100:
            /* This can't actually happen with current Trafficserver
             * versions, as TS will generate a 400 error without
             * reference to us.  But in case that changes in future ...
             */
            ib_log_error_tx(txndata->tx,
                            "No request headers found.");
            break;
          default:
            ib_log_error_tx(txndata->tx,
                            "Unhandled state arose in handling request headers.");
            break;
        }
    }
    if (request_inspection_finished) {
        if (!ib_flags_all(txndata->tx->flags, IB_TX_FREQ_STARTED) ) {
            ib_state_notify_request_started(txndata->tx->ib, txndata->tx, NULL);
        }
        if (!ib_flags_all(txndata->tx->flags, IB_TX_FREQ_FINISHED) ) {
            ib_state_notify_request_finished(txndata->tx->ib, txndata->tx);
        }
    }
    else {
        /* hook an input filter to watch data */
        TSHttpTxnHookAdd(txnp, TS_HTTP_REQUEST_TRANSFORM_HOOK,
                         txndata->in_data_cont);
    }
    /* Flag that we can no longer prevent a request going to backend */
    ib_tx_flags_set(txndata->tx, IB_TX_FSERVERREQ_STARTED);

    /* Check whether Ironbee told us to block the request.
     * This could now come not just from process_hdr, but also
     * from a brought-forward notification if we aren't inspecting
     * a request body and notified request_finished.
     */
    if (HTTP_CODE(txndata->status)) {
        TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp);
        TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR);
    }
    else {
        TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
    }
}
Exemple #22
0
static void ironbee_plugin_read_response_hdr(TSCont contp, TSHttpTxn txnp)
{
    assert(contp != NULL);
    assert(txnp != NULL);

    tsib_txn_ctx *txndata;
    tsib_hdr_outcome status;

    txndata = TSContDataGet(contp);

    if (txndata->tx == NULL) {
        TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
        return;
    }

    /* Feed ironbee the headers if not done already. */
    if (!ib_flags_all(txndata->tx->flags, IB_TX_FRES_STARTED)) {
        status = process_hdr(txndata, txnp, &tsib_direction_server_resp);

        /* OK, if this was an HTTP 100 response, it's not the
         * response we're interested in.  No headers have been
         * sent yet, and no data will be sent until we've
         * reached here again with the final response.
         */
        if (status == HDR_HTTP_100) {
            TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
            return;
        }
        // FIXME: Need to know if this fails as it (I think) means
        //        that the response did not come from the server and
        //        that ironbee should ignore it.
        /* I've not seen a fail here.  AFAICT if either the origin
         * isn't responding or we're responding from cache. we
         * never reach here in the first place.
         */
    }

    /* If ironbee signalled an error while processing request body data,
     * this is the first opportunity to divert to an errordoc
     */
    if (HTTP_CODE(txndata->status)) {
        ib_log_debug_tx(txndata->tx,
                        "HTTP code %d contp=%p", txndata->status, contp);
        TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp);
        TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR);
        return;
    }

    /* If we're not going to inspect response body data
     * we can bring forward notification of response-end
     * so we're in time to respond with an errordoc if Ironbee
     * wants to block in the response phase.
     *
     * This currently fails.  However, that appears to be because I
     * can't unset IB_TX_FINSPECT_RESBODY with InspectionEngineOptions
     */
    if (!ib_flags_all(txndata->tx->flags, IB_TX_FINSPECT_RESBODY)) {
        if (!ib_flags_all(txndata->tx->flags, IB_TX_FRES_STARTED) ) {
            ib_state_notify_response_started(txndata->tx->ib, txndata->tx, NULL);
        }
        if (!ib_flags_all(txndata->tx->flags, IB_TX_FRES_FINISHED) ) {
            ib_state_notify_response_finished(txndata->tx->ib, txndata->tx);
        }
        /* Test again for Ironbee telling us to block */
        if (HTTP_CODE(txndata->status)) {
            TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp);
            TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR);
            return;
        }
    }

    /* Flag that we're too late to divert to an error response */
    ib_tx_flags_set(txndata->tx, IB_TX_FCLIENTRES_STARTED);

    /* Normal execution.  Add output filter to inspect response. */
    TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK,
                     txndata->out_data_cont);
    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
}
static TSRemapStatus
ts_lua_remap_plugin_init(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;

    int remap     = (rri == NULL ? 0 : 1);
    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->has_hook = 0;
    http_ctx->rri      = rri;
    if (rri != NULL) {
        http_ctx->client_request_bufp = rri->requestBufp;
        http_ctx->client_request_hdrp = rri->requestHdrp;
        http_ctx->client_request_url  = rri->requestUrl;
    }

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

    lua_getglobal(L, (remap ? TS_LUA_FUNCTION_REMAP : TS_LUA_FUNCTION_OS_RESPONSE));
    if (lua_type(L, -1) != LUA_TFUNCTION) {
        TSMutexUnlock(main_ctx->mutexp);
        return TSREMAP_NO_REMAP;
    }

    ts_lua_set_cont_info(L, NULL);
    if (lua_pcall(L, 0, 1, 0) != 0) {
        TSError("[ts_lua] lua_pcall failed: %s", lua_tostring(L, -1));
        ret = TSREMAP_NO_REMAP;

    } else {
        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);
    }

    TSMutexUnlock(main_ctx->mutexp);

    return ret;
}
static void
handle_client_lookup(TSHttpTxn txnp, TSCont contp)
{
  TSMBuffer bufp;
  TSMLoc hdr_loc, url_loc;
  int host_length;

  in_addr_t clientip = 0;

  const char *host;

  if (TSIsDebugTagSet("redirect")) {
    struct sockaddr const *addr = TSHttpTxnClientAddrGet(txnp);

    if (addr) {
      socklen_t addr_size = 0;

      if (addr->sa_family == AF_INET) {
        addr_size = sizeof(struct sockaddr_in);
      } else if (addr->sa_family == AF_INET6) {
        addr_size = sizeof(struct sockaddr_in6);
      }
      if (addr_size > 0) {
        char clientstring[INET6_ADDRSTRLEN];

        if (NULL != inet_ntop(addr->sa_family, addr, clientstring, addr_size)) {
          TSDebug(PLUGIN_NAME, "clientip is %s and block_ip is %s", clientstring, block_ip);
        }
      }
    }
  }

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

  /*
   *   Check to see if the client is already headed to the redirect site.
   */
  if (strncmp(host, url_redirect, host_length) == 0) {
    TSHandleMLocRelease(bufp, hdr_loc, url_loc);
    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
    goto done;
  }

  /* TODO: This is odd, clientip is never set ... */
  if (ip_deny == clientip) {
    TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp);

    update_redirected_method_stats(bufp, hdr_loc);

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

    /*
     *   Increment the local redirect stat and do global update:
     */
    TSStatIntIncrement(requests_redirects, 1);

    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR);
    return;
  }

done:
  // Increment the local number unchanged stat and do global update:
  TSStatIntIncrement(requests_unchanged, 1);

  TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
}
Exemple #25
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 #26
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 #27
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;
}
Exemple #28
0
static int
transactionStartHookHandler(TSCont contp, TSEvent event ATS_UNUSED, void *edata)
{
  TSHttpTxn txnp = (TSHttpTxn) edata;

  uint64_t req_id;
  TSCont txn_contp;
  TSCont global_contp;

  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;

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

  global_contp = TSContCreate(globalHookHandler, NULL);
  TSContDataSet(global_contp, http_ctx);

  //adding hook based on whether the lua global function exists.
  lua_State *l = http_ctx->lua;

  lua_getglobal(l, TS_LUA_FUNCTION_G_SEND_REQUEST);
  if (lua_type(l, -1) == LUA_TFUNCTION) {
    TSHttpTxnHookAdd(txnp, 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) {
    TSHttpTxnHookAdd(txnp, 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) {
    TSHttpTxnHookAdd(txnp, 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) {
    TSHttpTxnHookAdd(txnp, 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) {
    TSHttpTxnHookAdd(txnp, 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) {
    TSHttpTxnHookAdd(txnp, 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) {
    TSHttpTxnHookAdd(txnp, 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) {
    TSHttpTxnHookAdd(txnp, 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) {
    TSHttpTxnHookAdd(txnp, 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) {
    TSHttpTxnHookAdd(txnp, 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) {
    TSHttpTxnHookAdd(txnp, 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) {
    TSHttpTxnHookAdd(txnp, TS_HTTP_TXN_CLOSE_HOOK, global_contp);
    TSDebug(TS_LUA_DEBUG_TAG, "txn_close_hook added");
  }
  lua_pop(l, 1);

  // add a hook to release resources for context
  TSHttpTxnHookAdd(txnp, TS_HTTP_TXN_CLOSE_HOOK, txn_contp);

  TSMutexUnlock(main_ctx->mutexp);

  TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
  return 0;
}
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 #30
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;
}