Пример #1
0
/**
 * Determine buffering policy from config settings
 *
 * @param[in] ibd - the filter descriptor
 * @param[in] tx - the transaction
 */
static void buffer_init(ibd_ctx *ibd, ib_tx_t *tx)
{
    ib_core_cfg_t *corecfg = NULL;
    ib_status_t rc;

    ib_filter_ctx *fctx = ibd->data;
    ib_server_direction_t dir = ibd->ibd->dir;

    if (tx == NULL) {
        fctx->buffering = IOBUF_NOBUF;
        return;
    }
    rc = ib_core_context_config(ib_context_main(tx->ib), &corecfg);
    if (rc != IB_OK) {
        TSError ("Error determining buffering configuration.");
    }
    else {
        if (dir == IBD_REQ) {
            fctx->buffering = (corecfg->buffer_req == 0)
                ? IOBUF_NOBUF :
                (corecfg->limits.request_body_buffer_limit < 0)
                    ? IOBUF_BUFFER_ALL :
                    (corecfg->limits.request_body_buffer_limit_action == IB_BUFFER_LIMIT_ACTION_FLUSH_ALL)
                        ? IOBUF_BUFFER_FLUSHALL
                        : IOBUF_BUFFER_FLUSHPART;
            fctx->buf_limit = (size_t) corecfg->limits.request_body_buffer_limit;
        }
        else {
            fctx->buffering = (corecfg->buffer_res == 0)
                ? IOBUF_NOBUF :
                (corecfg->limits.response_body_buffer_limit < 0)
                    ? IOBUF_BUFFER_ALL :
                    (corecfg->limits.response_body_buffer_limit_action == IB_BUFFER_LIMIT_ACTION_FLUSH_ALL)
                        ? IOBUF_BUFFER_FLUSHALL
                        : IOBUF_BUFFER_FLUSHPART;
            fctx->buf_limit = (size_t) corecfg->limits.response_body_buffer_limit;
        }
    }

    /* Override buffering based on flags */
    if (fctx->buffering != IOBUF_NOBUF) {
        if (dir == IBD_REQ) {
            if (ib_flags_any(tx->flags, IB_TX_FALLOW_ALL | IB_TX_FALLOW_REQUEST) ||
                (!ib_flags_all(tx->flags, IB_TX_FINSPECT_REQBODY) 
&&
                 !ib_flags_all(tx->flags, IB_TX_FINSPECT_REQHDR)) 
)
            {
                fctx->buffering = IOBUF_NOBUF;
                TSDebug("ironbee", "\tDisable request buffering");
            }
        } else if (dir == IBD_RESP) {
            if (ib_flags_any(tx->flags, IB_TX_FALLOW_ALL) ||
                (!ib_flags_all(tx->flags, IB_TX_FINSPECT_RESBODY) &&
                 !ib_flags_all(tx->flags, IB_TX_FINSPECT_RESHDR)) )
            {
                fctx->buffering = IOBUF_NOBUF;
                TSDebug("ironbee", "\tDisable response buffering");
            }
        }
    }
}
Пример #2
0
static void
add_header(TSHttpTxn txnp, TSCont contp)
{
  TSMBuffer req_bufp;
  TSMLoc req_loc;
  TSMLoc field_loc;
  TSMLoc next_field_loc;
  TSMLoc new_field_loc;
  int retval;

  if (TSHttpTxnClientReqGet(txnp, &req_bufp, &req_loc) != TS_SUCCESS) {
    TSError("[add_header] Error while retrieving client request header\n");
    goto done;
  }

  field_loc = TSMimeHdrFieldGet(hdr_bufp, hdr_loc, 0);
  if (field_loc == TS_NULL_MLOC) {
    TSError("[add_header] Error while getting field");
    goto error;
  }

  /* Loop on our header containing fields to add */
  while (field_loc) {

    /* First create a new field in the client request header */
    if (TSMimeHdrFieldCreate(req_bufp, req_loc, &new_field_loc) != TS_SUCCESS) {
      TSError("[add_header] Error while creating new field");
      TSHandleMLocRelease(hdr_bufp, hdr_loc, field_loc);
      break;
    }

    /* Then copy our new field at this new location */
    retval = TSMimeHdrFieldCopy(req_bufp, req_loc, new_field_loc, hdr_bufp, hdr_loc, field_loc);
    if (retval == TS_ERROR) {
      TSError("[add_header] Error while copying new field");
      TSHandleMLocRelease(hdr_bufp, hdr_loc, field_loc);
      break;
    }

    /* Add this field to the Http client request header */
    retval = TSMimeHdrFieldAppend(req_bufp, req_loc, new_field_loc);
    if (retval != TS_SUCCESS) {
      TSError("[add_header] Error while appending new field");
      TSHandleMLocRelease(hdr_bufp, hdr_loc, field_loc);
      break;
    }

    /* We can now release this handle */
    TSHandleMLocRelease(req_bufp, req_loc, new_field_loc);

    next_field_loc = TSMimeHdrFieldNext(hdr_bufp, hdr_loc, field_loc);
    TSHandleMLocRelease(hdr_bufp, hdr_loc, field_loc);
    field_loc = next_field_loc;
  }


error:
  TSHandleMLocRelease(req_bufp, TS_NULL_MLOC, req_loc);

done:
  TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
}
Пример #3
0
TSRemapStatus
TSRemapDoRemap(void *ih, TSHttpTxn rh, TSRemapRequestInfo *rri)
{
  int i, len;
  time_t t, e;
  MD5_CTX ctx;
  struct sockaddr_in *in;
  const char *qh, *ph, *ip;
  unsigned char md[MD5_DIGEST_LENGTH];
  secure_link_info *sli = (secure_link_info *)ih;
  char *token = NULL, *expire = NULL, *path = NULL;
  char *s, *ptr, *saveptr = NULL, *val, hash[32] = "";

  in = (struct sockaddr_in *)TSHttpTxnClientAddrGet(rh);
  ip = inet_ntoa(in->sin_addr);
  s = TSUrlStringGet(rri->requestBufp, rri->requestUrl, &len);
  TSDebug(PLUGIN_NAME, "request [%.*s] from [%s]", len, s, ip);
  TSfree(s);

  qh = TSUrlHttpQueryGet(rri->requestBufp, rri->requestUrl, &len);
  if (qh && len > 0) {
    s = (char *)TSstrndup(qh, len);
    if ((ptr = strtok_r(s, "&", &saveptr)) != NULL) {
      do {
        if ((val = strchr(ptr, '=')) != NULL) {
          *val++ = '\0';
          if (strcmp(ptr, "st") == 0) {
            token = TSstrdup(val);
          } else if (strcmp(ptr, "ex") == 0) {
            expire = TSstrdup(val);
          }
        } else {
          TSError("Invalid parameter [%s]", ptr);
          break;
        }
      } while ((ptr = strtok_r(NULL, "&", &saveptr)) != NULL);
    } else {
      TSError("strtok didn't find a & in the query string");
      /* this is just example, so set fake params to prevent plugin crash */
      token = TSstrdup("d41d8cd98f00b204e9800998ecf8427e");
      expire = TSstrdup("00000000");
    }
    TSfree(s);
  } else {
    TSError("TSUrlHttpQueryGet returns empty value");
  }

  ph = TSUrlPathGet(rri->requestBufp, rri->requestUrl, &len);
  if (ph && len > 0) {
    s = TSstrndup(ph, len);
    if ((ptr = strrchr(s, '/')) != NULL) {
      *++ptr = '\0';
    }
    path = TSstrdup(s);
    TSfree(s);
  } else {
    TSError("TSUrlPathGet returns empty value");
    /* this is just example, so set fake params to prevent plugin crash */
    path = TSstrdup("example/");
  }
  MD5_Init(&ctx);
  MD5_Update(&ctx, sli->secret, strlen(sli->secret));
  MD5_Update(&ctx, ip, strlen(ip));
  if (path)
    MD5_Update(&ctx, path, strlen(path));
  if (expire)
    MD5_Update(&ctx, expire, strlen(expire));
  MD5_Final(md, &ctx);
  for (i = 0; i < MD5_DIGEST_LENGTH; i++) {
    sprintf(&hash[i * 2], "%02x", md[i]);
  }
  time(&t);
  e = strtol(expire, NULL, 16);
  i = TSREMAP_DID_REMAP;
  if (e < t || strcmp(hash, token) != 0) {
    if (e < t) {
      TSDebug(PLUGIN_NAME, "link expired: [%lu] vs [%lu]", t, e);
    } else {
      TSDebug(PLUGIN_NAME, "tokens mismatch: [%s] vs [%s]", hash, token);
    }
    if (sli->strict) {
      TSDebug(PLUGIN_NAME, "request is DENY");
      TSHttpTxnSetHttpRetStatus(rh, TS_HTTP_STATUS_FORBIDDEN);
      i = TSREMAP_NO_REMAP;
    } else {
      TSDebug(PLUGIN_NAME, "request is PASS");
    }
  }
  if (i == TSREMAP_DID_REMAP) {
    if (TSUrlHttpQuerySet(rri->requestBufp, rri->requestUrl, "", -1) == TS_SUCCESS) {
      s = TSUrlStringGet(rri->requestBufp, rri->requestUrl, &len);
      TSDebug(PLUGIN_NAME, "new request string is [%.*s]", len, s);
      TSfree(s);
    } else {
      i = TSREMAP_NO_REMAP;
    }
  }
  TSfree(expire);
  TSfree(token);
  TSfree(path);
  return i;
}
Пример #4
0
/**
 * Handler function to generate an internal error response
 * when ironbee is unavailable to fill the fields or log errors.
 *
 * This may come from a TXN_START event, in which case we're
 * returning an HTTP/0.9 response and most of this is superfluous.
 */
static void internal_error_response(TSHttpTxn txnp)
{
    TSReturnCode rv;
    const char *reason = "Server Unavailable";
    TSMBuffer bufp;
    TSMLoc hdr_loc;
    TSMLoc field_loc;
    char *body;
    char clen[8];
    int i;
    const struct {
        const char *name;
        const char *val;
    } headers[2] = {
        { "Content-Type", "text/plain" },
        { "Content-Length", clen }
    };

    if (TSHttpTxnClientRespGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
        TSError("[ironbee] ErrorDoc: couldn't retrieve client response header.");
        return;
    }
    rv = TSHttpHdrStatusSet(bufp, hdr_loc, 503);
    if (rv != TS_SUCCESS) {
        TSError("[ironbee] ErrorDoc: TSHttpHdrStatusSet");
    }
    rv = TSHttpHdrReasonSet(bufp, hdr_loc, reason, strlen(reason));
    if (rv != TS_SUCCESS) {
        TSError("[ironbee] ErrorDoc: TSHttpHdrReasonSet");
    }

    /* this will free the body, so copy it first! */
    body = TSstrdup("Server unavailable or disabled.\n");

    snprintf(clen, sizeof(clen), "%zd", strlen(body));

    for (i = 0; i < 2; ++i) {
        rv = TSMimeHdrFieldCreate(bufp, hdr_loc, &field_loc);
        if (rv != TS_SUCCESS) {
            TSError("[ironbee] ErrorDoc: TSMimeHdrFieldCreate");
            continue;
        }
        rv = TSMimeHdrFieldNameSet(bufp, hdr_loc, field_loc,
                                   headers[i].name, strlen(headers[i].name));
        if (rv != TS_SUCCESS) {
            TSError("[ironbee] ErrorDoc: TSMimeHdrFieldNameSet");
            goto freehdr;
        }
        rv = TSMimeHdrFieldValueStringInsert(bufp, hdr_loc, field_loc, -1,
                                             headers[i].val, strlen(headers[i].val));
        if (rv != TS_SUCCESS) {
            TSError("[ironbee] ErrorDoc: TSMimeHdrFieldValueStringInsert");
            goto freehdr;
        }
        rv = TSMimeHdrFieldAppend(bufp, hdr_loc, field_loc);
        if (rv != TS_SUCCESS) {
            TSError("[ironbee] ErrorDoc: TSMimeHdrFieldAppend");
            goto freehdr;
        }

freehdr:
        rv = TSHandleMLocRelease(bufp, hdr_loc, field_loc);
        if (rv != TS_SUCCESS) {
            TSError("[ironbee] ErrorDoc: TSHandleMLocRelease 3");
            continue;
        }
    }

    TSHttpTxnErrorBodySet(txnp, body, strlen(body), NULL);

    rv = TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
    if (rv != TS_SUCCESS) {
        TSError("[ironbee] ErrorDoc: TSHandleMLocRelease 4");
    }
}
Пример #5
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)
{

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

        /* CONNECTION */
        case TS_EVENT_HTTP_SSN_START:
            ironbee_plugin_ssn_start(contp, (TSHttpSsn)edata);
            break;

        case TS_EVENT_HTTP_TXN_START:
            ironbee_plugin_txn_start(contp, (TSHttpTxn)edata);
            break;

        /* HTTP READ RESPONSE */
        case TS_EVENT_HTTP_READ_RESPONSE_HDR:
            ironbee_plugin_read_response_hdr(contp, (TSHttpTxn)edata);
            break;

        /* HTTP SEND RESPONSE */
        case TS_EVENT_HTTP_SEND_REQUEST_HDR:
            ironbee_plugin_send_request_hdr(contp, (TSHttpTxn)edata);
            break;

        /* Hook for processing response headers. */
        case TS_EVENT_HTTP_SEND_RESPONSE_HDR:
            ironbee_plugin_send_response_hdr(contp, (TSHttpTxn)edata);
            break;

        /* HTTP REQUEST */
        case TS_EVENT_HTTP_READ_REQUEST_HDR:
            ironbee_plugin_read_request_hdr(contp, (TSHttpTxn)edata);
            break;

        /* hook for processing incoming request/headers
         * The OS_DNS hook is an alternative here.
         */
        case TS_EVENT_HTTP_PRE_REMAP:
            ironbee_plugin_pre_remap(contp, (TSHttpTxn)edata);
            break;

        /* CLEANUP EVENTS */
        case TS_EVENT_HTTP_TXN_CLOSE:
            ironbee_plugin_txn_close(contp, (TSHttpTxn)edata);
            break;

        case TS_EVENT_HTTP_SSN_CLOSE:
            ironbee_plugin_ssn_close(contp, (TSHttpSsn)edata);
            break;

        case TS_EVENT_MGMT_UPDATE:
            ironbee_plugin_mgmt_update(contp);
            break;

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

    return 0;
}
Пример #6
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;

  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);
}
Пример #7
0
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;
}
Пример #8
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");
}
Пример #9
0
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;
}
Пример #10
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;
}
Пример #11
0
/* Generic error message function for errors in plugin initialization */
static void initialization_error(char *msg) {
    TSError("[%s] %s\n", PLUGIN_NAME, msg);
    TSError("[%s] Unable to initialize plugin (disabled).\n", PLUGIN_NAME);
}
Пример #12
0
static int regex_compile(regex_info **buf, char *pattern, char *replacement) {
    const char *reerror; /* Error string from pcre */
    int reerroffset;     /* Offset where any pcre error occured */

    int tokcount;
    int *tokens;
    int *tokenoffset;

    int i;

    int status = 1;      /* Status (return value) of the function */

    regex_info *info = TSmalloc(sizeof(regex_info));


    /* Precompile the regular expression */
    info->re =  pcre_compile(pattern, 0, &reerror, &reerroffset, NULL);
    if (!info->re) {
        TSError("[%s] Compilation of regex '%s' failed at char %d: %s\n",
                PLUGIN_NAME, pattern, reerroffset, reerror);
        status = 0;
    }

    /* Precalculate the location of $X tokens in the replacement */
    tokcount = 0;
    if (status) {
        tokens = TSmalloc(sizeof(int) * TOKENCOUNT);
        tokenoffset = TSmalloc(sizeof(int) * TOKENCOUNT);
        for (i=0; i<strlen(replacement); i++) {
            if (replacement[i] == '$') {
                if (tokcount >= TOKENCOUNT) {
                    TSError("[%s] Error: too many tokens in replacement "
                            "string: %s\n", PLUGIN_NAME, replacement);
                    status = 0;
                    break;
                } else if (replacement[i+1] < '0' || replacement[i+1] > '9') {
                    TSError("[%s] Error: Invalid replacement token $%c in "
                            "%s: should be $0 - $9\n", PLUGIN_NAME,
                            replacement[i+1], replacement);
                    status = 0;
                    break;
                } else {
                    /* Store the location of the replacement */
                    /* Convert '0' to 0 */
                    tokens[tokcount] = replacement[i+1] - '0';
                    tokenoffset[tokcount] = i;
                    tokcount++;
                    /* Skip the next char */
                    i++;
                }
            }
        }
    }

    if (status) {
        /* Everything went OK */
        info->tokcount = tokcount;
        info->tokens = tokens;
        info->tokenoffset = tokenoffset;

        info->pattern = TSstrdup(pattern);
        info->replacement = TSstrdup(replacement);

        *buf = info;
    } else {
        /* Something went wrong, clean up */
        if (info->tokens) TSfree(info->tokens);
        if (info->tokenoffset) TSfree(info->tokenoffset);
        if (info->re) pcre_free(info->re);
        if (info) TSfree(info);
    }
    return status;
}
Пример #13
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;
}
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");
}
Пример #15
0
/**
 * 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;
}
Пример #16
0
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;
}
Пример #17
0
static int
ts_lua_server_request_header_set(lua_State *L)
{
  const char *key;
  const char *val;
  size_t val_len;
  size_t key_len;
  int remove;
  int first;

  TSMLoc field_loc, tmp;

  ts_lua_http_ctx *http_ctx;

  GET_HTTP_CONTEXT(http_ctx, L);

  remove = 0;
  val    = NULL;

  /*   we skip the first argument that is the table */
  key = luaL_checklstring(L, 2, &key_len);
  if (lua_isnil(L, 3)) {
    remove = 1;
  } else {
    val = luaL_checklstring(L, 3, &val_len);
  }

  if (!http_ctx->server_request_hdrp) {
    if (TSHttpTxnServerReqGet(http_ctx->txnp, &http_ctx->server_request_bufp, &http_ctx->server_request_hdrp) != TS_SUCCESS) {
      return 0;
    }
  }

  field_loc = TSMimeHdrFieldFind(http_ctx->server_request_bufp, http_ctx->server_request_hdrp, key, key_len);

  if (remove) {
    while (field_loc != TS_NULL_MLOC) {
      tmp = TSMimeHdrFieldNextDup(http_ctx->server_request_bufp, http_ctx->server_request_hdrp, field_loc);
      TSMimeHdrFieldDestroy(http_ctx->server_request_bufp, http_ctx->server_request_hdrp, field_loc);
      TSHandleMLocRelease(http_ctx->server_request_bufp, http_ctx->server_request_hdrp, field_loc);
      field_loc = tmp;
    }
  } else if (field_loc != TS_NULL_MLOC) {
    first = 1;
    while (field_loc != TS_NULL_MLOC) {
      tmp = TSMimeHdrFieldNextDup(http_ctx->server_request_bufp, http_ctx->server_request_hdrp, field_loc);
      if (first) {
        first = 0;
        TSMimeHdrFieldValueStringSet(http_ctx->server_request_bufp, http_ctx->server_request_hdrp, field_loc, -1, val, val_len);
      } else {
        TSMimeHdrFieldDestroy(http_ctx->server_request_bufp, http_ctx->server_request_hdrp, field_loc);
      }
      TSHandleMLocRelease(http_ctx->server_request_bufp, http_ctx->server_request_hdrp, field_loc);
      field_loc = tmp;
    }
  } else if (TSMimeHdrFieldCreateNamed(http_ctx->server_request_bufp, http_ctx->server_request_hdrp, key, key_len, &field_loc) !=
             TS_SUCCESS) {
    TSError("[ts_lua][%s] TSMimeHdrFieldCreateNamed error", __FUNCTION__);
    return 0;

  } else {
    TSMimeHdrFieldValueStringSet(http_ctx->server_request_bufp, http_ctx->server_request_hdrp, field_loc, -1, val, val_len);
    TSMimeHdrFieldAppend(http_ctx->server_request_bufp, http_ctx->server_request_hdrp, field_loc);
  }

  if (field_loc != TS_NULL_MLOC) {
    TSHandleMLocRelease(http_ctx->server_request_bufp, http_ctx->server_request_hdrp, field_loc);
  }

  return 0;
}
Пример #18
0
int
ts_lua_add_module(ts_lua_instance_conf * conf, ts_lua_main_ctx * arr, int n, int argc, char *argv[])
{
  int i, ret;
  int t;
  lua_State *L;

  for (i = 0; i < n; i++) {
    conf->_first = (i == 0) ? 1 : 0;
    conf->_last = (i == n - 1) ? 1 : 0;

    TSMutexLock(arr[i].mutexp);

    L = arr[i].lua;

    lua_newtable(L);            /* new TB1 */
    lua_pushvalue(L, -1);       /* new TB2 */
    lua_setfield(L, -2, "_G");  /* TB1[_G] = TB2 empty table, we can change _G to xx */
    lua_newtable(L);            /* new TB3 */
    lua_rawgeti(L, LUA_REGISTRYINDEX, arr[i].gref);     /* push L[GLOBAL] */
    lua_setfield(L, -2, "__index");     /* TB3[__index] = L[GLOBAL] which has ts.xxx api */
    lua_setmetatable(L, -2);    /* TB1[META]  = TB3 */
    lua_replace(L, LUA_GLOBALSINDEX);   /* L[GLOBAL] = TB1 */

    ts_lua_set_instance_conf(L, conf);

    if (conf->content) {
      if (luaL_loadstring(L, conf->content)) {
        TSError("[%s] luaL_loadstring %s failed: %s", __FUNCTION__, conf->script, lua_tostring(L, -1));
        lua_pop(L, 1);
        TSMutexUnlock(arr[i].mutexp);
        return -1;
      }

    } else if (conf->script) { 
      if (luaL_loadfile(L, conf->script)) {
        TSError("[%s] luaL_loadfile %s failed: %s", __FUNCTION__, conf->script, lua_tostring(L, -1));
        lua_pop(L, 1);
        TSMutexUnlock(arr[i].mutexp);
        return -1;
      }
    }

    if (lua_pcall(L, 0, 0, 0)) {
      TSError("[%s] lua_pcall %s failed: %s", __FUNCTION__, conf->script, lua_tostring(L, -1));
      lua_pop(L, 1);
      TSMutexUnlock(arr[i].mutexp);
      return -1;
    }

    /* call "__init__", to parse parameters */
    lua_getglobal(L, "__init__");

    if (lua_type(L, -1) == LUA_TFUNCTION) {

      lua_newtable(L);

      for (t = 0; t < argc; t++) {
        lua_pushnumber(L, t);
        lua_pushstring(L, argv[t]);
        lua_rawset(L, -3);
      }

      if (lua_pcall(L, 1, 1, 0)) {
        TSError("[%s] lua_pcall %s failed: %s", __FUNCTION__, conf->script, lua_tostring(L, -1));
        lua_pop(L, 1);
        TSMutexUnlock(arr[i].mutexp);
        return -1;
      }

      ret = lua_tonumber(L, -1);
      lua_pop(L, 1);

      if (ret) {
        TSMutexUnlock(arr[i].mutexp);
        return -1;              /* script parse error */
      }

    } else {
      lua_pop(L, 1);            /* pop nil */
    }

    lua_pushlightuserdata(L, conf);
    lua_pushvalue(L, LUA_GLOBALSINDEX);
    lua_rawset(L, LUA_REGISTRYINDEX);   /* L[REG][conf] = L[GLOBAL] */

    lua_newtable(L);
    lua_replace(L, LUA_GLOBALSINDEX);   /* L[GLOBAL] = EMPTY */

    TSMutexUnlock(arr[i].mutexp);
  }

  return 0;
}
Пример #19
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_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
ts_lua_transform_handler(TSCont contp, ts_lua_http_transform_ctx *transform_ctx, TSEvent event, int n)
{
  TSVConn output_conn;
  TSVIO input_vio;
  TSIOBufferReader input_reader;
  TSIOBufferBlock blk;
  int64_t toread, towrite, blk_len, upstream_done, input_avail, input_wm_bytes, l;
  const char *start;
  const char *res;
  size_t res_len;
  int ret, eos, write_down, rc, top, empty_input;
  ts_lua_coroutine *crt;
  ts_lua_cont_info *ci;

  lua_State *L;
  TSMutex mtxp;

  ci  = &transform_ctx->cinfo;
  crt = &ci->routine;

  mtxp = crt->mctx->mutexp;
  L    = crt->lua;

  output_conn = TSTransformOutputVConnGet(contp);
  input_vio   = TSVConnWriteVIOGet(contp);

  empty_input = 0;
  if (!TSVIOBufferGet(input_vio)) {
    if (transform_ctx->output.vio) {
      TSDebug(TS_LUA_DEBUG_TAG, "[%s] reenabling output VIO after input VIO does not exist", __FUNCTION__);
      TSVIONBytesSet(transform_ctx->output.vio, transform_ctx->total);
      TSVIOReenable(transform_ctx->output.vio);
      return 0;
    } else {
      TSDebug(TS_LUA_DEBUG_TAG, "[%s] no input VIO and output VIO", __FUNCTION__);
      empty_input = 1;
    }
  } else { // input VIO exists
    input_wm_bytes = TSIOBufferWaterMarkGet(TSVIOBufferGet(input_vio));
    if (transform_ctx->upstream_watermark_bytes >= 0 && transform_ctx->upstream_watermark_bytes != input_wm_bytes) {
      TSDebug(TS_LUA_DEBUG_TAG, "[%s] Setting input_vio watermark to %" PRId64 " bytes", __FUNCTION__,
              transform_ctx->upstream_watermark_bytes);
      TSIOBufferWaterMarkSet(TSVIOBufferGet(input_vio), transform_ctx->upstream_watermark_bytes);
    }
  }

  if (empty_input == 0) {
    input_reader = TSVIOReaderGet(input_vio);
  }

  if (!transform_ctx->output.buffer) {
    transform_ctx->output.buffer = TSIOBufferCreate();
    transform_ctx->output.reader = TSIOBufferReaderAlloc(transform_ctx->output.buffer);

    transform_ctx->reserved.buffer = TSIOBufferCreate();
    transform_ctx->reserved.reader = TSIOBufferReaderAlloc(transform_ctx->reserved.buffer);

    if (empty_input == 0) {
      transform_ctx->upstream_bytes = TSVIONBytesGet(input_vio);
    } else {
      transform_ctx->upstream_bytes = 0;
    }

    transform_ctx->downstream_bytes = INT64_MAX;
  }

  if (empty_input == 0) {
    input_avail   = TSIOBufferReaderAvail(input_reader);
    upstream_done = TSVIONDoneGet(input_vio);
    toread        = TSVIONTodoGet(input_vio);

    if (toread <= input_avail) { // upstream finished
      eos = 1;
    } else {
      eos = 0;
    }
  } else {
    input_avail = 0;
    toread      = 0;
    eos         = 1;
  }

  if (input_avail > 0) {
    // move to the reserved.buffer
    TSIOBufferCopy(transform_ctx->reserved.buffer, input_reader, input_avail, 0);

    // reset input
    TSIOBufferReaderConsume(input_reader, input_avail);
    TSVIONDoneSet(input_vio, upstream_done + input_avail);
  }

  write_down = 0;
  if (empty_input == 0) {
    towrite = TSIOBufferReaderAvail(transform_ctx->reserved.reader);
  } else {
    towrite = 0;
  }

  TSMutexLock(mtxp);
  ts_lua_set_cont_info(L, ci);

  do {
    if (event == TS_LUA_EVENT_COROUTINE_CONT) {
      event = 0;
      goto launch;
    } else {
      n = 2;
    }

    if (towrite == 0 && empty_input == 0) {
      break;
    }

    if (empty_input == 0) {
      blk   = TSIOBufferReaderStart(transform_ctx->reserved.reader);
      start = TSIOBufferBlockReadStart(blk, transform_ctx->reserved.reader, &blk_len);

      lua_pushlightuserdata(L, transform_ctx);
      lua_rawget(L, LUA_GLOBALSINDEX); /* push function */

      if (towrite > blk_len) {
        lua_pushlstring(L, start, (size_t)blk_len);
        towrite -= blk_len;
        TSIOBufferReaderConsume(transform_ctx->reserved.reader, blk_len);
      } else {
        lua_pushlstring(L, start, (size_t)towrite);
        TSIOBufferReaderConsume(transform_ctx->reserved.reader, towrite);
        towrite = 0;
      }

      if (!towrite && eos) {
        lua_pushinteger(L, 1); /* second param, data finished */
      } else {
        lua_pushinteger(L, 0); /* second param, data not finish */
      }
    } else {
      lua_pushlightuserdata(L, transform_ctx);
      lua_rawget(L, LUA_GLOBALSINDEX); /* push function */

      lua_pushlstring(L, "", 0);
      lua_pushinteger(L, 1); /* second param, data finished */
    }

  launch:
    rc  = lua_resume(L, n);
    top = lua_gettop(L);

    switch (rc) {
    case LUA_YIELD: // coroutine yield
      TSMutexUnlock(mtxp);
      return 0;

    case 0: // coroutine success
      if (top == 2) {
        ret = lua_tointeger(L, -1); /* 0 is not finished, 1 is finished */
        res = lua_tolstring(L, -2, &res_len);
      } else { // what hells code are you writing ?
        ret     = 0;
        res     = NULL;
        res_len = 0;
      }
      break;

    default: // coroutine failed
      TSError("[ts_lua] lua_resume failed: %s", lua_tostring(L, -1));
      ret     = 1;
      res     = NULL;
      res_len = 0;
      break;
    }

    if (res && res_len > 0) {
      if (!transform_ctx->output.vio) {
        l = transform_ctx->downstream_bytes;
        if (ret) {
          l = res_len;
        }

        transform_ctx->output.vio = TSVConnWrite(output_conn, contp, transform_ctx->output.reader, l); // HttpSM go on
      }

      TSIOBufferWrite(transform_ctx->output.buffer, res, res_len);
      transform_ctx->total += res_len;
      write_down = 1;
    }

    lua_pop(L, top);

    if (ret || (eos && !towrite)) { // EOS
      eos = 1;
      break;
    }

  } while (towrite > 0);

  TSMutexUnlock(mtxp);

  if (eos && !transform_ctx->output.vio) {
    transform_ctx->output.vio = TSVConnWrite(output_conn, contp, transform_ctx->output.reader, 0);
  }

  if (write_down || eos) {
    TSVIOReenable(transform_ctx->output.vio);
  }

  if (toread > input_avail) { // upstream not finished.
    if (eos) {
      TSVIONBytesSet(transform_ctx->output.vio, transform_ctx->total);
      if (empty_input == 0) {
        TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_EOS, input_vio);
      }
    } else {
      if (empty_input == 0) {
        TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_READY, input_vio);
      }
    }
  } else { // upstream is finished.
    TSVIONBytesSet(transform_ctx->output.vio, transform_ctx->total);
    if (empty_input == 0) {
      TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_COMPLETE, input_vio);
    }
  }

  return 0;
}
Пример #21
0
void
TSPluginInit(int argc, const char *argv[])
{
  int ret = 0;
  ts_lua_g_main_ctx_array = TSmalloc(sizeof(ts_lua_main_ctx) * TS_LUA_MAX_STATE_COUNT);
  memset(ts_lua_g_main_ctx_array, 0, sizeof(ts_lua_main_ctx) * TS_LUA_MAX_STATE_COUNT);

  ret = ts_lua_create_vm(ts_lua_g_main_ctx_array, TS_LUA_MAX_STATE_COUNT);

  if (ret) {
    ts_lua_destroy_vm(ts_lua_g_main_ctx_array, TS_LUA_MAX_STATE_COUNT);
    TSfree(ts_lua_g_main_ctx_array);
    return;
  }

  if (argc < 2) {
    TSError("[%s] lua script file required !!", __FUNCTION__);
    return;
  }

  if (strlen(argv[1]) >= TS_LUA_MAX_SCRIPT_FNAME_LENGTH - 16) {
    TSError("[%s] lua script file name too long !!", __FUNCTION__);
    return;
  }

  ts_lua_instance_conf *conf = TSmalloc(sizeof(ts_lua_instance_conf));
  if (!conf) {
    TSError("[%s] TSmalloc failed !!", __FUNCTION__);
    return;
  }
  memset(conf, 0, sizeof(ts_lua_instance_conf));

  sprintf(conf->script, "%s", argv[1]);

  ts_lua_init_instance(conf);

  ret = ts_lua_add_module(conf, ts_lua_g_main_ctx_array, TS_LUA_MAX_STATE_COUNT, argc - 1, (char **) &argv[1]);

  if (ret != 0) {
    TSError("[%s] ts_lua_add_module failed", __FUNCTION__);
    return;
  }

  TSCont global_contp = TSContCreate(globalHookHandler, NULL);
  if (!global_contp) {
    TSError("[%s] could not create transaction start continuation", __FUNCTION__);
    return;
  }
  TSContDataSet(global_contp, conf);

  //adding hook based on whether the lua global function exists.
  ts_lua_main_ctx *main_ctx = &ts_lua_g_main_ctx_array[0];
  ts_lua_http_ctx *http_ctx = ts_lua_create_http_ctx(main_ctx, conf);
  lua_State *l = http_ctx->lua;

  lua_getglobal(l, TS_LUA_FUNCTION_G_SEND_REQUEST);
  if (lua_type(l, -1) == LUA_TFUNCTION) {
    TSHttpHookAdd(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) {
    TSHttpHookAdd(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) {
    TSHttpHookAdd(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) {
    TSHttpHookAdd(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) {
    TSHttpHookAdd(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) {
    TSHttpHookAdd(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) {
    TSHttpHookAdd(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) {
    TSHttpHookAdd(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) {
    TSHttpHookAdd(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) {
    TSHttpHookAdd(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) {
    TSHttpHookAdd(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) {
    TSHttpHookAdd(TS_HTTP_TXN_CLOSE_HOOK, global_contp);
    TSDebug(TS_LUA_DEBUG_TAG, "txn_close_hook added");
  }
  lua_pop(l, 1);

  ts_lua_destroy_http_ctx(http_ctx);

}
Пример #22
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;
}
Пример #23
0
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;
}
Пример #24
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);
    TSContScheduleOnPool(contp, RETRY_TIME, TS_THREAD_POOL_NET);
    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);
}
Пример #25
0
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("[PluginInit] Plugin registration failed.\n");
    goto error;
  }

  if (!check_ts_version()) {
    TSError("[PluginInit] Plugin requires Traffic Server 3.0 or later\n");
    goto error;
  }

  if (argc < 2) {
    TSError("[PluginInit] Usage: %s \"name1: value1\" \"name2: value2\" ...>\n", argv[0]);
    goto error;
  }

  hdr_bufp = TSMBufferCreate();
  if (TSMimeHdrCreate(hdr_bufp, &hdr_loc) != TS_SUCCESS) {
    TSError("[PluginInit] Can not create mime header");
    goto error;
  }

  for (i = 1; i < argc; i++) {
    if (TSMimeHdrFieldCreate(hdr_bufp, hdr_loc, &field_loc) != TS_SUCCESS) {
      TSError("[PluginInit] Error while creating field");
      goto error;
    }

    retval = TSMimeHdrFieldAppend(hdr_bufp, hdr_loc, field_loc);
    if (retval != TS_SUCCESS) {
      TSError("[PluginInit] Error while adding 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("[PluginInit] Error while naming 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("[PluginInit] Error while inserting field value");
        goto error;
      }
    } else {
      retval = TSMimeHdrFieldNameSet(hdr_bufp, hdr_loc, field_loc, argv[i], strlen(argv[i]));
      if (retval == TS_ERROR) {
        TSError("[PluginInit] Error while inserting field value");
        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("[PluginInit] Plugin not initialized");

done:
  return;
}
Пример #26
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);
}
Пример #27
0
static int
handle_buffering(TSCont contp, MyData * data)
{
  TSVIO write_vio;
  int towrite;
  int avail;

  /* Get the write VIO for the write operation that was performed on
     ourself. This VIO contains the buffer that we are to read from
     as well as the continuation we are to call when the buffer is
     empty. */
  write_vio = TSVConnWriteVIOGet(contp);

  /* Create the output buffer and its associated reader */
  if (!data->output_buffer) {
    data->output_buffer = TSIOBufferCreate();
    TSAssert(data->output_buffer);
    data->output_reader = TSIOBufferReaderAlloc(data->output_buffer);
    TSAssert(data->output_reader);
  }

  /* We also check to see if the write VIO's buffer is non-NULL. A
     NULL buffer indicates that the write operation has been
     shutdown and that the continuation does not want us to send any
     more WRITE_READY or WRITE_COMPLETE events. For this buffered
     transformation that means we're done buffering data. */

  if (!TSVIOBufferGet(write_vio)) {
    data->state = STATE_OUTPUT_DATA;
    return 0;
  }

  /* Determine how much data we have left to read. For this bnull
     transform plugin this is also the amount of data we have left
     to write to the output connection. */

  towrite = TSVIONTodoGet(write_vio);
  if (towrite > 0) {
    /* The amount of data left to read needs to be truncated by
       the amount of data actually in the read buffer. */

    avail = TSIOBufferReaderAvail(TSVIOReaderGet(write_vio));
    if (towrite > avail) {
      towrite = avail;
    }

    if (towrite > 0) {
      /* Copy the data from the read buffer to the input buffer. */
      TSIOBufferCopy(data->output_buffer, TSVIOReaderGet(write_vio), towrite, 0);

      /* Tell the read buffer that we have read the data and are no
         longer interested in it. */
      TSIOBufferReaderConsume(TSVIOReaderGet(write_vio), towrite);

      /* Modify the write VIO to reflect how much data we've
         completed. */
      TSVIONDoneSet(write_vio, TSVIONDoneGet(write_vio) + towrite);
    }
  }

  /* Now we check the write VIO to see if there is data left to read. */
  if (TSVIONTodoGet(write_vio) > 0) {
    if (towrite > 0) {
      /* Call back the write VIO continuation to let it know that we
         are ready for more data. */
      TSContCall(TSVIOContGet(write_vio), TS_EVENT_VCONN_WRITE_READY, write_vio);
    }
  } else {
    data->state = STATE_OUTPUT_DATA;

    /* Call back the write VIO continuation to let it know that we
       have completed the write operation. */
    TSContCall(TSVIOContGet(write_vio), TS_EVENT_VCONN_WRITE_COMPLETE, write_vio);
  }

  return 1;

  /* If we are in this code path then something is seriously wrong. */
  TSError("[bnull-transform] Fatal error in plugin");
  TSReleaseAssert(!"[bnull-transform] Fatal error in plugin\n");
  return 0;
}
Пример #28
0
/**
 * Function and struct to read a TS-style argc/argv commandline into
 * a config struct.  This struct is only used for ironbee_init, and
 * serves to enable new/revised options without disrupting the API or
 * load syntax.
 *
 * @param[in,out] mod_data Module data
 * @param[in] argc Command-line argument count
 * @param[in] argv Command-line argument list
 * @return  Success/Failure parsing the config line
 */
static ib_status_t read_ibconf(
    module_data_t *mod_data,
    int            argc,
    const char    *argv[]
)
{
    int c;

    /* defaults */
    mod_data->log_level = 4;

    /* const-ness mismatch looks like an oversight, so casting should be fine */
    while (c = getopt(argc, (char**)argv, "l:Lv:d:m:x:"), c != -1) {
        switch(c) {
        case 'L':
            mod_data->log_disable = true;
            break;
        case 'l':
            mod_data->log_file = strdup(optarg);
            break;
        case 'v':
            mod_data->log_level =
                ib_logger_string_to_level(optarg, IB_LOG_WARNING);
            break;
        case 'm':
            mod_data->max_engines = atoi(optarg);
            break;
        case 'x':
            mod_data->txlogfile = strdup(optarg);
            break;
        case '0':
            mod_data->allow_at_startup = true;
            break;
        default:
            TSError("[ironbee] Unrecognised option -%c ignored.", optopt);
            break;
        }
    }

    /* Default log file */
    if (mod_data->log_file == NULL) {
        mod_data->log_file = strdup(DEFAULT_LOG);
        if (mod_data->log_file == NULL) {
            return IB_EALLOC;
        }
    }

    /* keep the config file as a non-opt argument for back-compatibility */
    if (optind == argc-1) {
        mod_data->config_file = strdup(argv[optind]);
        if (mod_data->config_file == NULL) {
            return IB_EALLOC;
        }

        TSDebug("ironbee", "Configuration file: \"%s\"", mod_data->config_file);
        return IB_OK;
    }
    else {
        TSError("[ironbee] Exactly one configuration file name required.");
        return IB_EINVAL;
    }
}
Пример #29
0
static void
handle_dns(TSHttpTxn txnp, TSCont contp ATS_UNUSED)
{
  TSMBuffer bufp;
  TSMLoc hdr_loc;

  TSIOBuffer output_buffer;
  TSIOBufferReader reader;
  int total_avail;

  TSIOBufferBlock block;
  const char *block_start;
  int64_t block_avail;

  char *output_string;
  int64_t output_len;

  if (TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
    TSDebug(PLUGIN_NAME, "couldn't retrieve client request header");
    TSError("[%s] Couldn't retrieve client request header", PLUGIN_NAME);
    goto done;
  }

  output_buffer = TSIOBufferCreate();
  reader        = TSIOBufferReaderAlloc(output_buffer);

  /* This will print  just MIMEFields and not
     the http request line */
  TSDebug(PLUGIN_NAME, "Printing the hdrs ... ");
  TSMimeHdrPrint(bufp, hdr_loc, output_buffer);

  if (TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc) == TS_ERROR) {
    TSDebug(PLUGIN_NAME, "non-fatal: error releasing MLoc");
    TSError("[%s] non-fatal: Couldn't release MLoc", PLUGIN_NAME);
  }

  /* Find out how the big the complete header is by
     seeing the total bytes in the buffer.  We need to
     look at the buffer rather than the first block to
     see the size of the entire header */
  total_avail = TSIOBufferReaderAvail(reader);

  /* Allocate the string with an extra byte for the string
     terminator */
  output_string = (char *)TSmalloc(total_avail + 1);
  output_len    = 0;

  /* We need to loop over all the buffer blocks to make
     sure we get the complete header since the header can
     be in multiple blocks */
  block = TSIOBufferReaderStart(reader);
  while (block) {
    block_start = TSIOBufferBlockReadStart(block, reader, &block_avail);

    /* We'll get a block pointer back even if there is no data
       left to read so check for this condition and break out of
       the loop. A block with no data to read means we've exhausted
       buffer of data since if there was more data on a later
       block in the chain, this block would have been skipped over */
    if (block_avail == 0) {
      break;
    }

    memcpy(output_string + output_len, block_start, block_avail);
    output_len += block_avail;

    /* Consume the data so that we get to the next block */
    TSIOBufferReaderConsume(reader, block_avail);

    /* Get the next block now that we've consumed the
       data off the last block */
    block = TSIOBufferReaderStart(reader);
  }

  /* Terminate the string */
  output_string[output_len] = '\0';
  output_len++;

  /* Free up the TSIOBuffer that we used to print out the header */
  TSIOBufferReaderFree(reader);
  TSIOBufferDestroy(output_buffer);

  /* Although I'd never do this a production plugin, printf
     the header so that we can see it's all there */
  TSDebug(PLUGIN_NAME, "%s", output_string);

  TSfree(output_string);

done:
  TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
}
Пример #30
0
static void
modify_header(TSHttpTxn txnp)
{
  TSMBuffer resp_bufp;
  TSMBuffer cached_bufp;
  TSMLoc resp_loc;
  TSMLoc cached_loc;
  TSHttpStatus resp_status;
  TSMLoc new_field_loc;
  TSMLoc cached_field_loc;
  time_t recvd_time;

  const char *chkptr;
  int chklength;

  int num_refreshes = 0;

  if (!init_buffer_status)
    return; /* caller reenables */

  if (TSHttpTxnServerRespGet(txnp, &resp_bufp, &resp_loc) != TS_SUCCESS) {
    TSError("couldn't retrieve server response header\n");
    return; /* caller reenables */
  }

  /* TSqa06246/TSqa06144 */
  resp_status = TSHttpHdrStatusGet(resp_bufp, resp_loc);

  if (TS_HTTP_STATUS_OK == resp_status) {
    TSDebug("resphdr", "Processing 200 OK");
    TSMimeHdrFieldCreate(resp_bufp, resp_loc, &new_field_loc); /* Probably should check for errors */
    TSDebug("resphdr", "Created new resp field with loc %p", new_field_loc);

    /* copy name/values created at init
     * ( "x-num-served-from-cache" ) : ( "0"  )
     */
    TSMimeHdrFieldCopy(resp_bufp, resp_loc, new_field_loc, hdr_bufp, hdr_loc, field_loc);

    /*********** Unclear why this is needed **************/
    TSMimeHdrFieldAppend(resp_bufp, resp_loc, new_field_loc);


    /* Cache-Control: Public */
    TSMimeHdrFieldCreate(resp_bufp, resp_loc, &new_field_loc); /* Probably should check for errors */
    TSDebug("resphdr", "Created new resp field with loc %p", new_field_loc);
    TSMimeHdrFieldAppend(resp_bufp, resp_loc, new_field_loc);
    TSMimeHdrFieldNameSet(resp_bufp, resp_loc, new_field_loc, TS_MIME_FIELD_CACHE_CONTROL, TS_MIME_LEN_CACHE_CONTROL);
    TSMimeHdrFieldValueStringInsert(resp_bufp, resp_loc, new_field_loc, -1, TS_HTTP_VALUE_PUBLIC, TS_HTTP_LEN_PUBLIC);

    /*
     * mimehdr2_name  = TSstrdup( "x-date-200-recvd" ) : CurrentDateTime
     */
    TSMimeHdrFieldCreate(resp_bufp, resp_loc, &new_field_loc); /* Probably should check for errors */
    TSDebug("resphdr", "Created new resp field with loc %p", new_field_loc);
    TSMimeHdrFieldAppend(resp_bufp, resp_loc, new_field_loc);
    TSMimeHdrFieldNameSet(resp_bufp, resp_loc, new_field_loc, mimehdr2_name, strlen(mimehdr2_name));
    recvd_time = time(NULL);
    TSMimeHdrFieldValueDateInsert(resp_bufp, resp_loc, new_field_loc, recvd_time);

    TSHandleMLocRelease(resp_bufp, resp_loc, new_field_loc);
    TSHandleMLocRelease(resp_bufp, TS_NULL_MLOC, resp_loc);

  } else if (TS_HTTP_STATUS_NOT_MODIFIED == resp_status) {
    TSDebug("resphdr", "Processing 304 Not Modified");

    /* N.B.: Protect writes to data (hash on URL + mutex: (ies)) */

    /* Get the cached HTTP header */
    if (TSHttpTxnCachedRespGet(txnp, &cached_bufp, &cached_loc) != TS_SUCCESS) {
      TSError("STATUS 304, TSHttpTxnCachedRespGet():");
      TSError("couldn't retrieve cached response header\n");
      TSHandleMLocRelease(resp_bufp, TS_NULL_MLOC, resp_loc);
      return; /* Caller reenables */
    }

    /* Get the cached MIME field name for this HTTP header */
    cached_field_loc = TSMimeHdrFieldFind(cached_bufp, cached_loc, (const char *)mimehdr1_name, strlen(mimehdr1_name));
    if (TS_NULL_MLOC == cached_field_loc) {
      TSError("Can't find header %s in cached document", mimehdr1_name);
      TSHandleMLocRelease(resp_bufp, TS_NULL_MLOC, resp_loc);
      TSHandleMLocRelease(cached_bufp, TS_NULL_MLOC, cached_loc);
      return; /* Caller reenables */
    }

    /* Get the cached MIME value for this name in this HTTP header */
    chkptr = TSMimeHdrFieldValueStringGet(cached_bufp, cached_loc, cached_field_loc, -1, &chklength);
    if (NULL == chkptr || !chklength) {
      TSError("Could not find value for cached MIME field name %s", mimehdr1_name);
      TSHandleMLocRelease(resp_bufp, TS_NULL_MLOC, resp_loc);
      TSHandleMLocRelease(cached_bufp, TS_NULL_MLOC, cached_loc);
      TSHandleMLocRelease(cached_bufp, cached_loc, cached_field_loc);
      return; /* Caller reenables */
    }
    TSDebug("resphdr", "Header field value is %s, with length %d", chkptr, chklength);


    /* Get the cached MIME value for this name in this HTTP header */
    /*
       TSMimeHdrFieldValueUintGet(cached_bufp, cached_loc, cached_field_loc, 0, &num_refreshes);
       TSDebug("resphdr",
       "Cached header shows %d refreshes so far", num_refreshes );

       num_refreshes++ ;
     */

    /* txn origin server response for this transaction stored
    * in resp_bufp, resp_loc
    *
    * Create a new MIME field/value. Cached value has been incremented.
    * Insert new MIME field/value into the server response buffer,
    * allow HTTP processing to continue. This will update
    * (indirectly invalidates) the cached HTTP headers MIME field.
    * It is apparently not necessary to update all of the MIME fields
    * in the in-process response in order to have the cached response
    * become invalid.
  */
    TSMimeHdrFieldCreate(resp_bufp, resp_loc, &new_field_loc); /* Probaby should check for errrors */

    /* mimehdr1_name : TSstrdup( "x-num-served-from-cache" ) ; */

    TSMimeHdrFieldAppend(resp_bufp, resp_loc, new_field_loc);
    TSMimeHdrFieldNameSet(resp_bufp, resp_loc, new_field_loc, mimehdr1_name, strlen(mimehdr1_name));

    TSMimeHdrFieldValueUintInsert(resp_bufp, resp_loc, new_field_loc, -1, num_refreshes);

    TSHandleMLocRelease(resp_bufp, resp_loc, new_field_loc);
    TSHandleMLocRelease(cached_bufp, cached_loc, cached_field_loc);
    TSHandleMLocRelease(cached_bufp, TS_NULL_MLOC, cached_loc);
    TSHandleMLocRelease(resp_bufp, TS_NULL_MLOC, resp_loc);

  } else {
    TSDebug("resphdr", "other response code %d", resp_status);
  }

  /*
   *  Additional 200/304 processing can go here, if so desired.
   */

  /* Caller reneables */
}