/** * Initialize IronBee for ATS. * * Performs IB initializations for the ATS plugin. * * @param[in] mod_data Global module data * * @returns status */ static int ironbee_init(module_data_t *mod_data) { /* grab from httpd module's post-config */ ib_status_t rc; int rv; /* Create the channel. This is destroyed when the manager is destroyed. */ rc = ib_engine_manager_control_channel_create( &(mod_data->manager_ctl), ib_manager_mm(mod_data->manager), mod_data->manager); if (rc != IB_OK) { TSError("[ironbee] Error creating IronBee control channel: %s", ib_status_to_string(rc)); return rc; } /* Register the control commands (enable, disable, etc). * Failure is not fatal. */ rc = ib_engine_manager_control_manager_ctrl_register(mod_data->manager_ctl); if (rc != IB_OK) { TSError("[ironbee] Failed to register ctrl commands to ctrl channel."); } /* Register the diagnostic commands (version and valgrind). * Failure is not fatal. * The valgrind command does nothing when not compiled w/ valgrind. */ rc = ib_engine_manager_control_manager_diag_register(mod_data->manager_ctl); if (rc != IB_OK) { TSError("[ironbee] Failed to register diag commands to ctrl channel."); } /* Start the channel. This is stopped when it is destroyed. */ rc = ib_engine_manager_control_channel_start(mod_data->manager_ctl); if (rc != IB_OK) { TSError("[ironbee] Error starting IronBee control channel: %s", ib_status_to_string(rc)); /* Note: this is not a fatal error. */ } /* If we started the channel, schedule it for periodic execution. */ else { TSCont cont = TSContCreate(manager_ctl, TSMutexCreate()); TSContDataSet(cont, mod_data); TSContScheduleEvery( cont, /* Manager control continuation. */ CONTROL_CHANNEL_POLL_INTERVAL, /* Millisecons. */ TS_THREAD_POOL_TASK /* Task thread pool. */ ); } rc = ib_manager_engine_preconfig_fn_add( mod_data->manager, engine_preconfig_fn, mod_data); if (rc != IB_OK) { TSError("[ironbee] Error registering server preconfig function: %s", ib_status_to_string(rc)); return rc; } rc = ib_manager_engine_postconfig_fn_add( mod_data->manager, engine_postconfig_fn, mod_data); if (rc != IB_OK) { TSError("[ironbee] Error registering server postconfig function: %s", ib_status_to_string(rc)); return rc; } /* Create the initial engine */ TSDebug("ironbee", "Creating initial IronBee engine"); rc = ib_manager_engine_create(mod_data->manager, IB_MANAGER_ENGINE_NAME_DEFAULT, mod_data->config_file); if (rc != IB_OK) { TSError("[ironbee] Error creating initial IronBee engine: %s", ib_status_to_string(rc)); return rc; } /* Register our at exit function */ rv = atexit(ibexit); if (rv != 0) { TSError("[ironbee] Error registering IronBee exit handler: %s", strerror(rv)); return IB_EOTHER; } TSDebug("ironbee", "IronBee Ready"); return rc; }
static int ts_lua_get_shared_dict(lua_State *L) { char c; int n, i, option; int64_t quota; const char *name, *opt; size_t name_len, opt_len; ts_lua_shared_dict *dct; ts_lua_instance_conf *conf; n = lua_gettop(L); conf = ts_lua_get_instance_conf(L); if (n < 1) { return luaL_error(L, "ts.shared.DICT expecting name argument."); } name = lua_tolstring(L, 1, &name_len); if (name == NULL || name_len == 0) { return luaL_error(L, "The 1st param of ts.shared.DICT should be string"); } else if (name_len >= TS_LUA_MAX_SHARED_DICT_NAME_LENGTH - 4) { return luaL_error(L, "length of name for ts.shared.DICT is more than %d", TS_LUA_MAX_SHARED_DICT_NAME_LENGTH); } for (i = 0; i < conf->shdict_n; i++) { dct = &conf->shdict[i]; if (strlen(dct->name) == name_len && memcmp(dct->name, name, name_len) == 0) { lua_pushlightuserdata(L, dct); ts_lua_shared_dict_set_metatable(L); return 1; } } if (conf->shdict_n >= TS_LUA_MAX_SHARED_DICT_COUNT) return luaL_error(L, "There are too many shared dicts."); option = quota = 0; if (n == 2) { if (!lua_istable(L, 2)) { return luaL_error(L, "The 2nd param of ts.shared.DICT should be a table."); } /* quota */ lua_pushlstring(L, "quota", sizeof("quota") - 1); lua_gettable(L, 2); if (lua_isnil(L, -1)) { quota = 0; } else if (lua_isnumber(L, -1)) { quota = lua_tonumber(L, -1); } else { return luaL_error(L, "ts.shared.DICT: 'quota' is invalid"); } lua_pop(L, 1); /* option */ lua_pushlstring(L, "options", sizeof("options") - 1); lua_gettable(L, 2); if (lua_isstring(L, -1)) { opt = luaL_checklstring(L, -1, &opt_len); i = 0; while (i < opt_len) { c = *(opt + i); switch (c) { case 'i': option |= TS_LUA_SHDICT_FLAG_INTKEY; break; case 's': option |= TS_LUA_SHDICT_FLAG_STATIC; break; default: break; } i++; } } } dct = &(conf->shdict[conf->shdict_n++]); /* basic set */ snprintf(dct->name, TS_LUA_MAX_SHARED_DICT_NAME_LENGTH - 4, "%.*s", (int)name_len, name); dct->quota = quota; dct->flags = option; /* init hashtable */ if (option & TS_LUA_SHDICT_FLAG_INTKEY) { Tcl_InitHashTable(&(dct->map.t), TCL_ONE_WORD_KEYS); } else { Tcl_InitHashTable(&(dct->map.t), TCL_STRING_KEYS); } dct->map.mutexp = TSMutexCreate(); /* return to lua */ lua_pushlightuserdata(L, dct); ts_lua_shared_dict_set_metatable(L); return 1; }
static int astats_origin(TSCont cont, TSEvent event, void *edata) { TSCont icontp; stats_state *my_state; config_t* config; TSHttpTxn txnp = (TSHttpTxn) edata; TSMBuffer reqp; TSMLoc hdr_loc = NULL, url_loc = NULL; TSEvent reenable = TS_EVENT_HTTP_CONTINUE; config = get_config(cont); TSDebug(PLUGIN_TAG, "in the read stuff"); if (TSHttpTxnClientReqGet(txnp, &reqp, &hdr_loc) != TS_SUCCESS) goto cleanup; if (TSHttpHdrUrlGet(reqp, hdr_loc, &url_loc) != TS_SUCCESS) goto cleanup; int path_len = 0; const char* path = TSUrlPathGet(reqp,url_loc,&path_len); TSDebug(PLUGIN_TAG,"Path: %.*s",path_len,path); TSDebug(PLUGIN_TAG,"Path: %.*s",path_len,path); if (!(path_len == config->stats_path_len && !memcmp(path, config->stats_path, config->stats_path_len))) { // TSDebug(PLUGIN_TAG, "not right path: %.*s",path_len,path); goto notforme; } const struct sockaddr *addr = TSHttpTxnClientAddrGet(txnp); if(!is_ip_allowed(config, addr)) { TSDebug(PLUGIN_TAG, "not right ip"); goto notforme; } // TSDebug(PLUGIN_TAG,"Path...: %.*s",path_len,path); int query_len; char *query = (char*)TSUrlHttpQueryGet(reqp,url_loc,&query_len); TSDebug(PLUGIN_TAG,"query: %.*s",query_len,query); TSSkipRemappingSet(txnp,1); //not strictly necessary, but speed is everything these days /* This is us -- register our intercept */ TSDebug(PLUGIN_TAG, "Intercepting request"); icontp = TSContCreate(stats_dostuff, TSMutexCreate()); my_state = (stats_state *) TSmalloc(sizeof(*my_state)); memset(my_state, 0, sizeof(*my_state)); my_state->recordTypes = config->recordTypes; if (query_len) { my_state->query = nstrl(query, query_len); TSDebug(PLUGIN_TAG,"new query: %s", my_state->query); stats_fillState(my_state, my_state->query, query_len); } TSContDataSet(icontp, my_state); TSHttpTxnIntercept(icontp, txnp); goto cleanup; notforme: cleanup: #if (TS_VERSION_NUMBER < 2001005) if (path) TSHandleStringRelease(reqp, url_loc, path); #endif if (url_loc) TSHandleMLocRelease(reqp, hdr_loc, url_loc); if (hdr_loc) TSHandleMLocRelease(reqp, TS_NULL_MLOC, hdr_loc); TSHttpTxnReenable(txnp, reenable); return 0; }
void TSPluginInit(int argc, const char *argv[]) { TSPluginRegistrationInfo info; TSCont pre_remap_cont, post_remap_cont, global_cont; config_t *config; info.plugin_name = PLUGIN_NAME; info.vendor_name = "Apache Software Foundation"; info.support_email = "*****@*****.**"; if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) { TSError("Plugin registration failed."); return; } else TSDebug(DEBUG_TAG, "Plugin registration succeeded."); config = TSmalloc(sizeof(config_t)); config->post_remap_host = false; config->persist_type = TS_STAT_NON_PERSISTENT; config->stat_creation_mutex = TSMutexCreate(); if (argc > 1) { int c; optind = 1; static const struct option longopts[] = { {"post-remap-host", no_argument, NULL, 'P'}, {"persistent", no_argument, NULL, 'p'}, {NULL, 0, NULL, 0} }; while ((c = getopt_long(argc, (char *const *) argv, "Pp", longopts, NULL)) != -1) { switch (c) { case 'P': config->post_remap_host = true; TSDebug(DEBUG_TAG, "Using post remap hostname"); break; case 'p': config->persist_type = TS_STAT_PERSISTENT; TSDebug(DEBUG_TAG, "Using persistent stats"); break; default: break; } } } TSHttpArgIndexReserve(PLUGIN_NAME, "txn data", &(config->txn_slot)); if (!config->post_remap_host) { pre_remap_cont = TSContCreate(handle_read_req_hdr, NULL); TSContDataSet(pre_remap_cont, (void *) config); TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, pre_remap_cont); } post_remap_cont = TSContCreate(handle_post_remap, NULL); TSContDataSet(post_remap_cont, (void *) config); TSHttpHookAdd(TS_HTTP_POST_REMAP_HOOK, post_remap_cont); global_cont = TSContCreate(handle_txn_close, NULL); TSContDataSet(global_cont, (void *) config); TSHttpHookAdd(TS_HTTP_TXN_CLOSE_HOOK, global_cont); TSDebug(DEBUG_TAG, "Init complete"); }
/** * 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; }
void TSPluginInit(int argc, const char *argv[]) { TSPluginRegistrationInfo info; TSCont main_cont, config_cont; plugin_state_t *pstate; invalidate_t *iptr = NULL; bool disable_timed_reload = false; TSDebug(LOG_PREFIX, "Starting plugin init"); pstate = (plugin_state_t *)TSmalloc(sizeof(plugin_state_t)); init_plugin_state_t(pstate); int c; static const struct option longopts[] = {{"config", required_argument, NULL, 'c'}, {"log", required_argument, NULL, 'l'}, {"disable-timed-reload", no_argument, NULL, 'd'}, {NULL, 0, NULL, 0}}; while ((c = getopt_long(argc, (char *const *)argv, "c:l:", longopts, NULL)) != -1) { switch (c) { case 'c': pstate->config_file = TSstrdup(optarg); break; case 'l': if (TS_SUCCESS == TSTextLogObjectCreate(optarg, TS_LOG_MODE_ADD_TIMESTAMP, &pstate->log)) { TSTextLogObjectRollingEnabledSet(pstate->log, 1); TSTextLogObjectRollingIntervalSecSet(pstate->log, LOG_ROLL_INTERVAL); TSTextLogObjectRollingOffsetHrSet(pstate->log, LOG_ROLL_OFFSET); } break; case 'd': disable_timed_reload = true; break; default: break; } } if (!pstate->config_file) { TSError("[regex_revalidate] Plugin requires a --config option along with a config file name"); free_plugin_state_t(pstate); return; } if (!load_config(pstate, &iptr)) { TSDebug(LOG_PREFIX, "Problem loading config from file %s", pstate->config_file); } else { pstate->invalidate_list = iptr; list_config(pstate, iptr); } info.plugin_name = LOG_PREFIX; info.vendor_name = "Apache Software Foundation"; info.support_email = "*****@*****.**"; if (TSPluginRegister(&info) != TS_SUCCESS) { TSError("[regex_revalidate] Plugin registration failed"); free_plugin_state_t(pstate); return; } else { TSDebug(LOG_PREFIX, "Plugin registration succeeded"); } if (!check_ts_version()) { TSError("[regex_revalidate] Plugin requires Traffic Server %d.%d.%d", TS_VERSION_MAJOR, TS_VERSION_MINOR, TS_VERSION_MICRO); free_plugin_state_t(pstate); return; } pcre_malloc = &ts_malloc; pcre_free = &ts_free; main_cont = TSContCreate(main_handler, NULL); TSContDataSet(main_cont, (void *)pstate); TSHttpHookAdd(TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK, main_cont); config_cont = TSContCreate(config_handler, TSMutexCreate()); TSContDataSet(config_cont, (void *)pstate); TSMgmtUpdateRegister(config_cont, LOG_PREFIX); if (!disable_timed_reload) { TSContScheduleOnPool(config_cont, CONFIG_TMOUT, TS_THREAD_POOL_TASK); } TSDebug(LOG_PREFIX, "Plugin Init Complete"); }
void TSPluginInit(int argc, const char *argv[]) { TSMLoc field_loc; const char *p; int i, retval; TSPluginRegistrationInfo info; info.plugin_name = "add-header"; info.vendor_name = "MyCompany"; info.support_email = "*****@*****.**"; if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) { TSError("[add_header] Plugin registration failed."); goto error; } if (argc < 2) { TSError("[add_header] Usage: %s \"name1: value1\" \"name2: value2\" ...>", argv[0]); goto error; } hdr_bufp = TSMBufferCreate(); if (TSMimeHdrCreate(hdr_bufp, &hdr_loc) != TS_SUCCESS) { TSError("[add_header] Can not create mime header"); goto error; } for (i = 1; i < argc; i++) { if (TSMimeHdrFieldCreate(hdr_bufp, hdr_loc, &field_loc) != TS_SUCCESS) { TSError("[add_header] Unable to create field"); goto error; } retval = TSMimeHdrFieldAppend(hdr_bufp, hdr_loc, field_loc); if (retval != TS_SUCCESS) { TSError("[add_header] Unable to add field"); goto error; } p = strchr(argv[i], ':'); if (p) { retval = TSMimeHdrFieldNameSet(hdr_bufp, hdr_loc, field_loc, argv[i], p - argv[i]); if (retval == TS_ERROR) { TSError("[add_header] Unable to name field"); goto error; } p += 1; while (isspace(*p)) { p += 1; } retval = TSMimeHdrFieldValueStringInsert(hdr_bufp, hdr_loc, field_loc, -1, p, strlen(p)); if (retval == TS_ERROR) { TSError("[add_header] Unable to insert field value"); goto error; } } else { retval = TSMimeHdrFieldNameSet(hdr_bufp, hdr_loc, field_loc, argv[i], strlen(argv[i])); if (retval == TS_ERROR) { TSError("[add_header] Unable to set field name"); goto error; } } } /* Create a continuation with a mutex as there is a shared global structure containing the headers to add */ TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, TSContCreate(add_header_plugin, TSMutexCreate())); goto done; error: TSError("[add_header] Plugin not initialized"); done: return; }
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; /* Find the last /, essentially memrchr (which does not exist on macOS) */ while ((s_path >= 0) && ('/' != path[s_path])) { --s_path; } if (((path_len - s_path - 1) == purge->secret_len) && !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()); TSDebug(PLUGIN_NAME, "Setting up continuation for PURGE operation"); TSContDataSet(cont, purge); TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, cont); update_purge_state(purge); } else if (purge->gen_id > 0) { TSDebug(PLUGIN_NAME, "Setting request gen_id to %" PRId64, purge->gen_id); TSHttpTxnConfigIntSet(txnp, TS_CONFIG_HTTP_CACHE_GENERATION, purge->gen_id); } }