/*------------------------------------------------------------------------- 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; }
/** * Process data from ATS. * * Process data from one of the ATS events. * * @param[in,out] contp - the continuation * @param[in,out] ibd - the filter descriptor */ static void process_data(TSCont contp, ibd_ctx *ibd) { int64_t ntodo; int64_t navail; TSIOBufferReader input_reader, output_reader; TSIOBufferBlock block; const char *buf; int64_t nbytes; ib_status_t rc; ib_filter_ctx *fctx = ibd->data; ib_txn_ctx *data = TSContDataGet(contp); TSVIO input_vio = TSVConnWriteVIOGet(contp); TSIOBuffer in_buf = TSVIOBufferGet(input_vio); /* Test whether we're going into an errordoc */ if (IB_HTTP_CODE(data->status)) { /* We're going to an error document, * so we discard all this data */ TSDebug("ironbee", "Status is %d, discarding", data->status); ibd->data->buffering = IOBUF_DISCARD; } /* Test for EOS */ if (in_buf == NULL) { /* flush anything we have buffered. This is final! */ flush_data(fctx, -1, 1); return; } ntodo = TSVIONTodoGet(input_vio); /* Test for first time, and initialise. */ if (!fctx->output_buffer) { fctx->output_buffer = TSIOBufferCreate(); ib_mm_register_cleanup(data->tx->mm, (ib_mm_cleanup_fn_t) TSIOBufferDestroy, (void*) fctx->output_buffer); output_reader = TSIOBufferReaderAlloc(fctx->output_buffer); fctx->output_vio = TSVConnWrite(TSTransformOutputVConnGet(contp), contp, output_reader, TSVIONBytesGet(input_vio)); fctx->buffer = TSIOBufferCreate(); ib_mm_register_cleanup(data->tx->mm, (ib_mm_cleanup_fn_t) TSIOBufferDestroy, (void*) fctx->buffer); fctx->reader = TSIOBufferReaderAlloc(fctx->buffer); /* Get the buffering config */ if (!IB_HTTP_CODE(data->status)) { buffer_init(ibd, data->tx); } /* Do we still have to delay feeding the first data to Ironbee * to keep the IB events in their proper order? * * Appears maybe not, so let's do nothing until it shows signs of breakage. */ #if BUFFER_FIRST /* First time through we can only buffer data until headers are sent. */ fctx->first_time = 1; input_reader = TSVIOReaderGet(input_vio); fctx->buffered = TSIOBufferCopy(fctx->buffer, TSVIOReaderGet(input_vio), ntodo, 0); TSIOBufferReaderConsume(input_reader, fctx->buffered); /* Do we need to request more input or just continue? */ TSVIONDoneSet(input_vio, fctx->buffu`ered + fctx->bytes_done); TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_READY, input_vio); return; #endif } /* second time through we have to feed already-buffered data through * ironbee while retaining it in buffer. Regardless of what else happens. */ #if BUFFER_FIRST if (fctx->first_time) { fctx->first_time = 0; for (block = TSIOBufferStart(fctx->buffer); block != NULL; block = TSIOBufferBlockNext(block)) { //nbytes = TSIOBufferBlockDataSizeGet(block); /* FIXME - do this without a reader ? */ buf = TSIOBufferBlockReadStart(block, fctx->reader, &nbytes); //rc = examine_data_chunk(ibd->ibd, data->tx, buf, nbytes); rc = (*ibd->ibd->ib_notify_body)(data->tx->ib, data->tx, buf, nbytes); if (rc != IB_OK) { // FIXME ??? } } } #endif /* Test for EOS */ if (ntodo == 0) { TSDebug("[ironbee]", "ntodo zero before consuming data"); /* Call back the input VIO continuation to let it know that we * have completed the write operation. */ TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_COMPLETE, input_vio); return; } /* OK, there's some input awaiting our attention */ input_reader = TSVIOReaderGet(input_vio); while (navail = TSIOBufferReaderAvail(input_reader), navail > 0) { block = TSIOBufferReaderStart(input_reader); buf = TSIOBufferBlockReadStart(block, input_reader, &nbytes); rc = (*ibd->ibd->ib_notify_body)(data->tx->ib, data->tx, buf, nbytes); if (rc != IB_OK) { // FIXME ??? } rc = buffer_data_chunk(fctx, input_reader, nbytes); if (rc != IB_OK) { // FIXME ??? } TSIOBufferReaderConsume(input_reader, nbytes); TSVIONDoneSet(input_vio, TSVIONDoneGet(input_vio) + nbytes); } ntodo = TSVIONTodoGet(input_vio); if (ntodo == 0) { TSDebug("[ironbee]", "ntodo zero after consuming data"); /* Call back the input VIO continuation to let it know that we * have completed the write operation. */ TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_COMPLETE, input_vio); } else { /* Call back the input VIO continuation to let it know that we * are ready for more data. */ TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_READY, input_vio); } }