Esempio n. 1
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;
}
Esempio n. 2
0
static void ironbee_plugin_ssn_start(TSCont contp, TSHttpSsn ssnp)
{
    assert(contp != NULL);
    assert(ssnp != NULL);

    TSCont mycont;
    tsib_ssn_ctx *ssndata;

    /* 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
    */
    mycont = TSContCreate(ironbee_plugin, NULL);
    TSHttpSsnHookAdd (ssnp, TS_HTTP_TXN_START_HOOK, mycont);
    ssndata = TSmalloc(sizeof(*ssndata));
    memset(ssndata, 0, sizeof(*ssndata));
    ssndata->contp = mycont;
    TSContDataSet(mycont, ssndata);

    TSHttpSsnHookAdd (ssnp, TS_HTTP_SSN_CLOSE_HOOK, mycont);

    TSHttpSsnReenable (ssnp, TS_EVENT_HTTP_CONTINUE);
}
Esempio n. 3
0
static int
ssn_handler(TSCont contp, TSEvent event, void *edata)
{
  TSHttpSsn ssnp;
  TSHttpTxn txnp;

  switch (event) {
  case TS_EVENT_HTTP_SSN_START:

    ssnp = (TSHttpSsn)edata;
    handle_session(ssnp, contp);
    TSHttpSsnReenable(ssnp, TS_EVENT_HTTP_CONTINUE);
    return 0;

  case TS_EVENT_HTTP_TXN_START:
    txnp = (TSHttpTxn)edata;
    txn_handler(txnp, contp);
    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
    return 0;

  default:
    TSDebug("tag_session", "In the default case: event = %d", event);
    break;
  }
  return 0;
}
Esempio n. 4
0
static void ironbee_plugin_ssn_close(TSCont contp, TSHttpSsn ssnp)
{
    assert(contp != NULL);

    TSDebug("ironbee", "SSN Close: %p", (void *)contp);
    tsib_ssn_ctx_destroy(TSContDataGet(contp));
    tsib_manager_engine_cleanup();
    TSHttpSsnReenable(ssnp, TS_EVENT_HTTP_CONTINUE);
}
Esempio n. 5
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;
}
Esempio n. 6
0
/**
 * Plugin for the IronBee ATS.
 *
 * Handles some ATS events.
 *
 * @param[in,out] contp Pointer to the continuation
 * @param[in,out] event Event from ATS
 * @param[in,out] edata Event data
 *
 * @returns status
 */
int ironbee_plugin(TSCont contp, TSEvent event, void *edata)
{
    ib_status_t rc;
    TSCont mycont;
    TSHttpTxn txnp = (TSHttpTxn) edata;
    TSHttpSsn ssnp = (TSHttpSsn) edata;
    tsib_txn_ctx *txndata;
    tsib_ssn_ctx *ssndata;
    tsib_hdr_outcome status;
    TSMutex ts_mutex = NULL;

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

        /* CONNECTION */
        case TS_EVENT_HTTP_SSN_START:
            /* start of connection */
            /* But we can't initialize conn stuff here, because there's
             * no API to get the connection stuff required by ironbee
             * at this point.  So instead, intercept the first TXN
             *
             * what we can and must do: create a new contp whose
             * lifetime is our ssn
             */
            ts_mutex = TSMutexCreate();
            mycont = TSContCreate(ironbee_plugin, ts_mutex);
            TSHttpSsnHookAdd (ssnp, TS_HTTP_TXN_START_HOOK, mycont);
            ssndata = TSmalloc(sizeof(*ssndata));
            memset(ssndata, 0, sizeof(*ssndata));
            /* The only failure here is EALLOC, and if that happens
             * we're ****ed anyway
             */
            rc = ib_lock_create_malloc(&(ssndata->mutex));
            assert(rc == IB_OK);
            ssndata->contp = mycont;
            ssndata->ts_mutex = ts_mutex;
            TSContDataSet(mycont, ssndata);

            TSHttpSsnHookAdd (ssnp, TS_HTTP_SSN_CLOSE_HOOK, mycont);

            TSHttpSsnReenable (ssnp, TS_EVENT_HTTP_CONTINUE);
            break;

        case TS_EVENT_HTTP_TXN_START:
        {
            /* start of Request */
            /* First req on a connection, we set up conn stuff */
            ib_status_t  rc;
            ib_engine_t *ib = NULL;

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

            if (ssndata->iconn == NULL) {
                rc = tsib_manager_engine_acquire(&ib);
                if (rc == IB_DECLINED) {
                    /* OK, this means the manager is disabled deliberately,
                     * but otherwise all's well.  So this TXN
                     * gets processed without intervention from Ironbee
                     * and is invisble when our SSN_CLOSE hook runs.
                     */
                    ib_lock_unlock(ssndata->mutex);
                    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
                    TSDebug("ironbee", "Decline from engine manager");
                    break;
                }
                else if (rc != IB_OK) {
                    TSError("[ironbee] Failed to acquire engine: %s",
                            ib_status_to_string(rc));
                    goto noib_error;
                }
                if (ib != NULL) {
                    rc = ib_conn_create(ib, &ssndata->iconn, contp);
                    if (rc != IB_OK) {
                        TSError("[ironbee] ib_conn_create: %s",
                                ib_status_to_string(rc));
                        tsib_manager_engine_release(ib);
                        goto noib_error;
                    }

                    /* In the normal case, release the engine when the
                     * connection's memory pool is destroyed */
                    rc = ib_mm_register_cleanup(ssndata->iconn->mm,
                                                cleanup_ib_connection,
                                                ib);
                    if (rc != IB_OK) {
                        TSError("[ironbee] ib_mm_register_cleanup: %s",
                                ib_status_to_string(rc));
                        tsib_manager_engine_release(ib);
                        goto noib_error;
                    }

                    TSDebug("ironbee", "CONN CREATE: conn=%p", ssndata->iconn);
                    ssndata->txnp = txnp;
                    ssndata->txn_count = ssndata->closing = 0;

                    rc = ironbee_conn_init(ssndata);
                    if (rc != IB_OK) {
                        TSError("[ironbee] ironbee_conn_init: %s",
                                ib_status_to_string(rc));
                        goto noib_error;
                    }

                    TSContDataSet(contp, ssndata);
                    TSDebug("ironbee",
                            "ironbee_plugin: ib_state_notify_conn_opened()");
                    rc = ib_state_notify_conn_opened(ib, ssndata->iconn);
                    if (rc != IB_OK) {
                        TSError("[ironbee] Failed to notify connection opened: %s",
                                ib_status_to_string(rc));
                    }
                }
                else {
                    /* Use TSError where there's no ib or tx */
                    TSError("Ironbee: No ironbee engine!");
                    goto noib_error;
                }
            }

            /* create a txn cont (request ctx) and tx */
            txndata = TSmalloc(sizeof(*txndata));
            memset(txndata, 0, sizeof(*txndata));
            txndata->ssn = ssndata;
            txndata->txnp = txnp;

            rc = ib_tx_create(&txndata->tx, ssndata->iconn, txndata);
            if (rc != IB_OK) {
                TSError("[ironbee] Failed to create tx: %d", rc);
                tsib_manager_engine_release(ib);
                TSfree(txndata);
                goto noib_error;
            }

            ++ssndata->txn_count;
            ib_lock_unlock(ssndata->mutex);

            ib_log_debug_tx(txndata->tx,
                            "TX CREATE: conn=%p tx=%p id=%s txn_count=%d",
                            ssndata->iconn, txndata->tx, txndata->tx->id,
                            txndata->ssn->txn_count);

            mycont = TSContCreate(ironbee_plugin, ssndata->ts_mutex);
            TSContDataSet(mycont, txndata);

            TSHttpTxnHookAdd(txnp, TS_HTTP_TXN_CLOSE_HOOK, mycont);

            /* Hook to process responses */
            TSHttpTxnHookAdd(txnp, TS_HTTP_READ_RESPONSE_HDR_HOOK, mycont);

            /* Hook to process requests */
            TSHttpTxnHookAdd(txnp, TS_HTTP_READ_REQUEST_HDR_HOOK, mycont);

            /* Create continuations for input and output filtering
             * to give them txn lifetime.
             */
            txndata->in_data_cont = TSTransformCreate(in_data_event, txnp);
            TSContDataSet(txndata->in_data_cont, txndata);

            txndata->out_data_cont = TSTransformCreate(out_data_event, txnp);
            TSContDataSet(txndata->out_data_cont, txndata);

            TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
            break;

noib_error:
            ib_lock_unlock(ssndata->mutex);

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

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

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

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

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

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

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

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

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

            break;

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

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

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

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

            TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
            break;

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

            TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
            break;

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

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


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

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

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

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

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

    return 0;
}