static void list_config(plugin_state_t *pstate, invalidate_t *i) { invalidate_t *iptr; TSDebug(LOG_PREFIX, "Current config:"); if (pstate->log) { TSTextLogObjectWrite(pstate->log, "Current config:"); } if (i) { iptr = i; while (iptr) { TSDebug(LOG_PREFIX, "%s epoch: %d expiry: %d", iptr->regex_text, (int)iptr->epoch, (int)iptr->expiry); if (pstate->log) { TSTextLogObjectWrite(pstate->log, "%s epoch: %d expiry: %d", iptr->regex_text, (int)iptr->epoch, (int)iptr->expiry); } iptr = iptr->next; } } else { TSDebug(LOG_PREFIX, "EMPTY"); if (pstate->log) { TSTextLogObjectWrite(pstate->log, "EMPTY"); } } }
static void ironbee_logger(void *dummy, int level, const char *prefix, const char *file, int line, const char *fmt, va_list ap) { char buf[8192 + 1]; int limit = 7000; int ec; TSReturnCode rc; const char *errmsg = NULL; /* Buffer the log line. */ ec = vsnprintf(buf, sizeof(buf), fmt, ap); if (ec >= limit) { /* Mark as truncated, with a " ...". */ memcpy(buf + (limit - 5), " ...", 5); errmsg = "Data truncated in log"; } /* Write it to the ironbee log. */ /* FIXME: why is the format arg's prototype not const char* ? */ rc = prefix ? TSTextLogObjectWrite(ironbee_log, (char*)"%s: %s", prefix, buf) : TSTextLogObjectWrite(ironbee_log, (char*)"%s", buf); if (rc != TS_SUCCESS) { errmsg = "Data logging failed!"; } if (errmsg != NULL) TSError("[ts-ironbee] %s\n", errmsg); }
/** * Handle a single log record. This is a @ref ib_logger_standard_msg_t. * * @param[in] element A @ref ib_logger_standard_msg_t holding * a serialized transaction log to be written to the * Traffic Server transaction log. * @param[in] cbdata A @ref module_data_t. */ static void txlog_record_element( void *element, void *cbdata ) { assert(element != NULL); assert(cbdata != NULL); ib_logger_standard_msg_t *msg = (ib_logger_standard_msg_t *)element; module_data_t *mod_data = (module_data_t *)cbdata; /* FIXME - expand msg->msg with Traffic Server variables. */ /* I don't understand what is TBD here! */ if (!mod_data->txlogger) { /* txlogging off */ return; } /* write log file. */ if (msg->msg != NULL) { /* In practice, this is always NULL for txlogs. */ if (msg->prefix != NULL) { TSTextLogObjectWrite(mod_data->txlogger, "%s %.*s", msg->prefix, (int)msg->msg_sz, (const char *)msg->msg); } else { TSTextLogObjectWrite(mod_data->txlogger, "%.*s", (int)msg->msg_sz, (const char *)msg->msg); } /* FIXME: once debugged, take this out for speed */ TSTextLogObjectFlush(mod_data->txlogger); } }
static void protocol_init(int accept_port, int server_port ATS_UNUSED) { TSCont contp; int ret_val; /* create customized log */ ret_val = TSTextLogObjectCreate("protocol", TS_LOG_MODE_ADD_TIMESTAMP, &protocol_plugin_log); if (ret_val != TS_SUCCESS) { TSError("[protocol] Failed to create log"); } /* format of the log entries, for caching_status, 1 for HIT and 0 for MISS */ ret_val = TSTextLogObjectWrite(protocol_plugin_log, "timestamp filename servername caching_status\n\n"); if (ret_val != TS_SUCCESS) { TSError("[protocol] Failed to write into log"); } contp = TSContCreate(accept_handler, TSMutexCreate()); /* Accept network traffic from the accept_port. When there are requests coming in, contp's handler should be called, in this case, contp's handler is accept_event, see AcceptSM.c */ pending_action = TSNetAccept(contp, accept_port, -1, 1); }
/** * Log a message to the server plugin. * * @param[in] ib_logger The IronBee logger. * @param[in] rec The record to use in logging. * @param[in] log_msg The user's log message. * @param[in] log_msg_sz The user's log message size. * @param[out] writer_record Unused. We always return IB_DECLINED. * @param[in] cbdata The server plugin module data used for logging. * * @returns * - IB_DECLINED when everything goes well. * - IB_OK is not returned. * - Other on error. */ static ib_status_t logger_format( ib_logger_t *ib_logger, const ib_logger_rec_t *rec, const uint8_t *log_msg, const size_t log_msg_sz, void *writer_record, void *cbdata ) { assert(ib_logger != NULL); assert(rec != NULL); assert(log_msg != NULL); assert(cbdata != NULL); if (cbdata == NULL) { return IB_DECLINED; } module_data_t *mod_data = (module_data_t *)cbdata; TSTextLogObject logger = mod_data->logger; if (logger == NULL) { return IB_DECLINED; } if (log_msg == NULL || log_msg_sz == 0) { TSTextLogObjectFlush(logger); } else { ib_logger_standard_msg_t *std_msg = NULL; ib_status_t rc = ib_logger_standard_formatter_notime( ib_logger, rec, log_msg, log_msg_sz, &std_msg, NULL); if (rc != IB_OK) { return rc; } TSTextLogObjectWrite( logger, "%s %.*s", std_msg->prefix, (int)std_msg->msg_sz, (const char *)std_msg->msg); ib_logger_standard_msg_free(ib_logger, std_msg, cbdata); } return IB_DECLINED; }
static void list_config(config_holder_t *config_holder, invalidate_t *i) { invalidate_t *iptr; TSDebug(PLUGIN_TAG, "Current config:"); if (config_holder->log) TSTextLogObjectWrite(config_holder->log, "Current config:"); if (i) { iptr = i; while (iptr) { TSDebug(PLUGIN_TAG, "%s epoch: %d expiry: %d", iptr->regex_text, (int)iptr->epoch, (int)iptr->expiry); if (config_holder->log) TSTextLogObjectWrite(config_holder->log, "%s epoch: %d expiry: %d", iptr->regex_text, (int)iptr->epoch, (int)iptr->expiry); iptr = iptr->next; } } else { TSDebug(PLUGIN_TAG, "EMPTY"); if (config_holder->log) TSTextLogObjectWrite(config_holder->log, "EMPTY"); } }
static int ts_lua_log_object_write(lua_State *L) { const char *text; size_t text_len; text = luaL_checklstring(L, 1, &text_len); if (log) { TSTextLogObjectWrite(log, (char *)text, NULL); } else { TSError("[ts_lua][%s] log object does not exist for write", __FUNCTION__); } return 0; }
static int rewrite_cacheurl(pr_list *prl, TSHttpTxn txnp) { int ok = 1; char *newurl = 0; int retval; char *url; int url_length; int i; if (ok) { url = TSHttpTxnEffectiveUrlStringGet(txnp, &url_length); if (!url) { TSError("[%s] couldn't retrieve request url\n", PLUGIN_NAME); ok = 0; } } if (ok) { i=0; while (i < prl->patterncount && prl->pr[i]) { retval = regex_substitute(&newurl, url, prl->pr[i]); if (retval) { /* Successful match/substitution */ break; } i++; } if (newurl) { if (log) { TSTextLogObjectWrite(log, "Rewriting cache URL for %s to %s", url, newurl); } TSDebug(PLUGIN_NAME, "Rewriting cache URL for %s to %s\n", url, newurl); if (TSCacheUrlSet(txnp, newurl, strlen(newurl)) != TS_SUCCESS) { TSError("[%s] Unable to modify cache url from " "%s to %s\n", PLUGIN_NAME, url, newurl); ok = 0; } } } /* Clean up */ if (url) TSfree(url); if (newurl) TSfree(newurl); return ok; }
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); }
/*------------------------------------------------------------------------- psi_include Read file to include. Copy its content into an iobuffer. This is the function doing blocking calls and called by the plugin's threads Input: data continuation for the current transaction Output : data->psi_buffer contains the file content data->psi_sucess 0 if include failed, 1 if success Return Value: 0 if failure 1 if success -------------------------------------------------------------------------*/ static int psi_include(TSCont contp, void *edata) { #define BUFFER_SIZE 1024 ContData *data; TSFile filep; char buf[BUFFER_SIZE]; char inc_file[PSI_PATH_MAX_SIZE + PSI_FILENAME_MAX_SIZE]; /* We manipulate plugin continuation data from a separate thread. Grab mutex to avoid concurrent access */ TSMutexLock(TSContMutexGet(contp)); data = TSContDataGet(contp); TSAssert(data->magic == MAGIC_ALIVE); if (!data->psi_buffer) { data->psi_buffer = TSIOBufferCreate(); data->psi_reader = TSIOBufferReaderAlloc(data->psi_buffer); } /* For security reason, we do not allow to include files that are not in the directory <plugin_path>/include. Also include file cannot contain any path. */ sprintf(inc_file, "%s/%s", psi_directory, _basename(data->psi_filename)); /* Read the include file and copy content into iobuffer */ if ((filep = TSfopen(inc_file, "r")) != NULL) { TSDebug(DBG_TAG, "Reading include file %s", inc_file); while (TSfgets(filep, buf, BUFFER_SIZE) != NULL) { TSIOBufferBlock block; int64_t len, avail, ndone, ntodo, towrite; char *ptr_block; len = strlen(buf); ndone = 0; ntodo = len; while (ntodo > 0) { /* TSIOBufferStart allocates more blocks if required */ block = TSIOBufferStart(data->psi_buffer); ptr_block = TSIOBufferBlockWriteStart(block, &avail); towrite = MIN(ntodo, avail); memcpy(ptr_block, buf + ndone, towrite); TSIOBufferProduce(data->psi_buffer, towrite); ntodo -= towrite; ndone += towrite; } } TSfclose(filep); data->psi_success = 1; if (log) { TSTextLogObjectWrite(log, "Successfully included file: %s", inc_file); } } else { data->psi_success = 0; if (log) { TSTextLogObjectWrite(log, "Failed to include file: %s", inc_file); } } /* Change state and schedule an event EVENT_IMMEDIATE on the plugin continuation to let it know we're done. */ /* Note: if the blocking call was not in the transformation state (i.e. in TS_HTTP_READ_REQUEST_HDR, TS_HTTP_OS_DNS and so on...) we could use TSHttpTxnReenable to wake up the transaction instead of sending an event. */ TSContSchedule(contp, 0, TS_THREAD_POOL_DEFAULT); data->psi_success = 0; data->state = STATE_READ_DATA; TSMutexUnlock(TSContMutexGet(contp)); return 0; }
static pr_list* load_config_file(const char *config_file) { char buffer[1024]; char default_config_file[1024]; TSFile fh; pr_list *prl = TSmalloc(sizeof(pr_list)); prl->patterncount = 0; /* locations in a config file line, end of line, split start, split end */ char *eol, *spstart, *spend; int lineno = 0; int retval; regex_info *info = 0; if (!config_file) { /* Default config file of plugins/cacheurl.config */ sprintf(default_config_file, "%s/cacheurl.config", TSPluginDirGet()); config_file = (const char *)default_config_file; } TSDebug(PLUGIN_NAME, "Opening config file: %s", config_file); fh = TSfopen(config_file, "r"); if (!fh) { TSError("[%s] Unable to open %s. No patterns will be loaded\n", PLUGIN_NAME, config_file); return prl; } while (TSfgets(fh, buffer, sizeof(buffer) - 1)) { lineno++; if (*buffer == '#') { /* # Comments, only at line beginning */ continue; } eol = strstr(buffer, "\n"); if (eol) { *eol = 0; /* Terminate string at newline */ } else { /* Malformed line - skip */ continue; } /* Split line into two parts based on whitespace */ /* Find first whitespace */ spstart = strstr(buffer, " "); if (!spstart) { spstart = strstr(buffer, "\t"); } if (!spstart) { TSError("[%s] ERROR: Invalid format on line %d. Skipping\n", PLUGIN_NAME, lineno); continue; } /* Find part of the line after any whitespace */ spend = spstart + 1; while(*spend == ' ' || *spend == '\t') { spend++; } if (*spend == 0) { /* We reached the end of the string without any non-whitepace */ TSError("[%s] ERROR: Invalid format on line %d. Skipping\n", PLUGIN_NAME, lineno); continue; } *spstart = 0; /* We have the pattern/replacement, now do precompilation. * buffer is the first part of the line. spend is the second part just * after the whitespace */ if (log) { TSTextLogObjectWrite(log, "Adding pattern/replacement pair: '%s' -> '%s'", buffer, spend); } TSDebug(PLUGIN_NAME, "Adding pattern/replacement pair: '%s' -> '%s'\n", buffer, spend); retval = regex_compile(&info, buffer, spend); if (!retval) { TSError("[%s] Error precompiling regex/replacement. Skipping.\n", PLUGIN_NAME); } // TODO - remove patterncount and make pr_list infinite (linked list) if (prl->patterncount >= PATTERNCOUNT) { TSError("[%s] Warning, too many patterns - skipping the rest" "(max: %d)\n", PLUGIN_NAME, PATTERNCOUNT); TSfree(info); break; } prl->pr[prl->patterncount] = info; prl->patterncount++; } TSfclose(fh); // Make sure the last element is null if (prl->patterncount < PATTERNCOUNT) { prl->pr[prl->patterncount] = NULL; } return prl; }