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; }
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); }
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; }
/*------------------------------------------------------------------------- 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; }
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; }
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; }
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); } }
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; }
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); } }
/** * 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; }
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; }
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); }
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); } }
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); }
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; }
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; }
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; }
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); }
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; }