Example #1
0
void
ts_http_fetcher_add_header(http_fetcher *fch, const char *name, int name_len, const char *value, int value_len)
{
    if (name_len == TS_MIME_LEN_CONTENT_LENGTH && 
            memcmp(name, TS_MIME_FIELD_CONTENT_LENGTH, name_len) == 0) {      // for POST
        fch->post_cl = atoll(value);
    }

    TSIOBufferWrite(fch->req_buffer, name, name_len);
    TSIOBufferWrite(fch->req_buffer, ": ", sizeof(": ")-1);
    TSIOBufferWrite(fch->req_buffer, value, value_len);
    TSIOBufferWrite(fch->req_buffer, "\r\n", sizeof("\r\n")-1);
}
Example #2
0
void
ts_http_fetcher_launch(http_fetcher *fch)
{
    int64_t     hdr_len;
    // post body , content-length

    TSIOBufferWrite(fch->req_buffer, "\r\n", sizeof("\r\n")-1);
    hdr_len = TSIOBufferReaderAvail(fch->req_reader);

    fch->http_vc = TSHttpConnect(&(fch->aip));

    fch->hdr_buffer = TSIOBufferSizedCreate(TS_IOBUFFER_SIZE_INDEX_8K);
    fch->hdr_reader = TSIOBufferReaderAlloc(fch->hdr_buffer);
    fch->hdr_bufp = TSMBufferCreate();
    fch->hdr_loc = TSHttpHdrCreate(fch->hdr_bufp);

    fch->resp_buffer = TSIOBufferCreate();
    fch->resp_reader = TSIOBufferReaderAlloc(fch->resp_buffer);
    fch->http_parser = TSHttpParserCreate();

    fch->fetch_contp = TSContCreate(ts_http_fetch_handler, fch->mutexp);
    TSContDataSet(fch->fetch_contp, fch);

    fch->read_vio = TSVConnRead(fch->http_vc, fch->fetch_contp, fch->resp_buffer, INT64_MAX);

    if (fch->method == TS_FETCH_METHOD_POST && fch->post_cl >= 0) {
        fch->write_vio = TSVConnWrite(fch->http_vc, fch->fetch_contp, fch->req_reader, hdr_len + fch->post_cl);
    } else {
        fch->write_vio = TSVConnWrite(fch->http_vc, fch->fetch_contp, fch->req_reader, hdr_len);
    }

    fch->launched = 1;
}
static int
handle_output(TSCont contp, JCrusherData * data)
{
  const char *output;
  int64_t written_bytes;

  /* Check to see if we need to initiate the output operation. */
  TSDebug("jcrusher", "Start of handle_output()");
  if (!data->downstream_vio) {
    TSVConn output_conn;

    /* Get the json_object as string and write it into buffer */
    output = json_object_to_json_string_ext(data->json_obj, JSON_C_TO_STRING_PLAIN);
    written_bytes = TSIOBufferWrite(data->downstream_buffer, output, (int64_t)(strlen(output)));
    TSDebug("jcrusher", "handle_output - Just write %" PRId64 " bytes to ouput", written_bytes);
    /* Get the output connection where we'll write data to. */
    output_conn = TSTransformOutputVConnGet(contp);
    data->downstream_vio =
      TSVConnWrite(output_conn, contp, data->downstream_reader, TSIOBufferReaderAvail(data->downstream_reader));

    TSAssert(data->downstream_vio);
  }
  TSDebug("jcrusher", "End of handle_output()");
  return 1;
}
static int
ts_lua_http_intercept_run_coroutine(ts_lua_http_intercept_ctx * ictx)
{
  int ret;
  const char *res;
  size_t res_len;
  lua_State *L;

  L = ictx->lua;

  ret = lua_resume(L, 0);

  switch (ret) {

  case 0:                      // finished
    res = lua_tolstring(L, -1, &res_len);
    ts_lua_http_intercept_setup_write(ictx);
    TSIOBufferWrite(ictx->output.buffer, res, res_len);
    TSVIONBytesSet(ictx->output.vio, res_len);
    break;

  case 1:                      // yield
    break;

  default:                     // error
    fprintf(stderr, "lua_resume failed: %s\n", lua_tostring(L, -1));
    return -1;
  }

  return 0;
}
Example #5
0
void
ts_http_fetcher_append_data(http_fetcher *fch, const char *data, int len)
{
    TSIOBufferWrite(fch->req_buffer, data, len);

    if (fch->launched)
        TSVIOReenable(fch->write_vio);
}
static int
stats_add_data_to_resp_buffer(const char *s, stats_state *my_state) {
	int s_len = strlen(s);

	TSIOBufferWrite(my_state->resp_buffer, s, s_len);

	return s_len;
}
Example #7
0
static int
transform_connect(TSCont contp, TransformData *data)
{
  TSAction action;
  int content_length;
  struct sockaddr_in ip_addr;

  data->state = STATE_CONNECT;

  content_length = TSIOBufferReaderAvail(data->input_reader);
  if (content_length >= 0) {
    data->content_length = content_length;
    data->content_length = htonl(data->content_length);

    /* Prepend the content length to the buffer.
     * If we decide to not send the content to the transforming
     * server then we need to make sure and skip input_reader
     * over the content length.
     */

    {
      TSIOBuffer temp;
      TSIOBufferReader tempReader;

      temp       = TSIOBufferCreate();
      tempReader = TSIOBufferReaderAlloc(temp);

      TSIOBufferWrite(temp, (const char *)&content_length, sizeof(int));
      TSIOBufferCopy(temp, data->input_reader, content_length, 0);

      TSIOBufferReaderFree(data->input_reader);
      TSIOBufferDestroy(data->input_buf);
      data->input_buf    = temp;
      data->input_reader = tempReader;
    }
  } else {
    TSError("[%s] TSIOBufferReaderAvail returns TS_ERROR", PLUGIN_NAME);
    return 0;
  }

  /* TODO: This only supports IPv4, probably should be changed at some point, but
     it's an example ... */
  memset(&ip_addr, 0, sizeof(ip_addr));
  ip_addr.sin_family      = AF_INET;
  ip_addr.sin_addr.s_addr = server_ip; /* Should be in network byte order */
  ip_addr.sin_port        = server_port;
  TSDebug(PLUGIN_NAME, "net connect.");
  action = TSNetConnect(contp, (struct sockaddr const *)&ip_addr);

  if (!TSActionDone(action)) {
    data->pending_action = action;
  }

  return 0;
}
Example #8
0
void
ts_http_fetcher_append_data(http_fetcher *fch, const char *data, int len)
{
    if (len <= 0 || fch->body_done)
        return;

    TSIOBufferWrite(fch->req_buffer, data, len);

    if (fch->launched)
        TSVIOReenable(fch->write_vio);
}
Example #9
0
void
ts_http_fetcher_init_common(http_fetcher *fch, int method, const char *uri, int uri_len)
{
    char    buf[2048];
    int     n;

    fch->method = method;
    n = sprintf(buf, "%s %.*s HTTP/1.1\r\n", http_method_str[method], uri_len,uri);

    TSIOBufferWrite(fch->req_buffer, buf, n);
}
Example #10
0
int
ts_chunked_process(TSIOBufferReader readerp, TSIOBuffer bufp, int end)
{
    char    hex[32];
    int     n;
    int64_t avail;

    avail = TSIOBufferReaderAvail(readerp);

    if (avail) {
        n = snprintf(hex, sizeof(hex), "%llx\r\n", (long long)avail);

        TSIOBufferWrite(bufp, hex, n);
        TSIOBufferCopy(bufp, readerp, avail, 0);
        TSIOBufferWrite(bufp, "\r\n", sizeof("\r\n") - 1);

        TSIOBufferReaderConsume(readerp, avail);
    }

    if (end)
        TSIOBufferWrite(bufp, "0\r\n\r\n", sizeof("0\r\n\r\n") - 1);

    return end;
}
Example #11
0
void
ts_http_fetcher_init(http_fetcher *fch, const char *method, int method_len, const char *uri, int uri_len)
{
    char    buf[2048];
    int     n;

    if (uri_len >= sizeof(buf) - 64)
        uri_len = sizeof(buf) - 64;

    if (method_len == TS_HTTP_LEN_GET && !strncasecmp(method, TS_HTTP_METHOD_GET, TS_HTTP_LEN_GET)) {
        fch->method = TS_FETCH_HTTP_METHOD_GET;
        n = sprintf(buf, "GET %.*s HTTP/1.1\r\n", uri_len, uri);

    } else if (method_len == TS_HTTP_LEN_POST && !strncasecmp(method, TS_HTTP_METHOD_POST, TS_HTTP_LEN_POST)) {
        fch->method = TS_FETCH_HTTP_METHOD_POST;
        n = sprintf(buf, "POST %.*s HTTP/1.1\r\n", uri_len, uri);

    } else if (method_len == TS_HTTP_LEN_CONNECT && !strncasecmp(method, TS_HTTP_METHOD_CONNECT, TS_HTTP_LEN_CONNECT)) {
        fch->method = TS_FETCH_HTTP_METHOD_CONNECT;
        n = sprintf(buf, "CONNECT %.*s HTTP/1.1\r\n", uri_len, uri);

    } else if (method_len == TS_HTTP_LEN_DELETE && !strncasecmp(method, TS_HTTP_METHOD_DELETE, TS_HTTP_LEN_DELETE)) {
        fch->method = TS_FETCH_HTTP_METHOD_DELETE;
        n = sprintf(buf, "DELETE %.*s HTTP/1.1\r\n", uri_len, uri);

    } else if (method_len == TS_HTTP_LEN_HEAD && !strncasecmp(method, TS_HTTP_METHOD_HEAD, TS_HTTP_LEN_HEAD)) {
        fch->method = TS_FETCH_HTTP_METHOD_HEAD;
        n = sprintf(buf, "HEAD %.*s HTTP/1.1\r\n", uri_len, uri);

    } else if (method_len == TS_HTTP_LEN_PURGE && !strncasecmp(method, TS_HTTP_METHOD_PURGE, TS_HTTP_LEN_PURGE)) {
        fch->method = TS_FETCH_HTTP_METHOD_PURGE;
        n = sprintf(buf, "PURGE %.*s HTTP/1.1\r\n", uri_len, uri);

    } else if (method_len == TS_HTTP_LEN_PUT && !strncasecmp(method, TS_HTTP_METHOD_PUT, TS_HTTP_LEN_PUT)) {
        fch->method = TS_FETCH_HTTP_METHOD_PUT;
        n = sprintf(buf, "PUT %.*s HTTP/1.1\r\n", uri_len, uri);

    } else {

        if (method_len >= 16)
            method_len = 16;

        n = sprintf(buf, "%.*s %.*s HTTP/1.1\r\n", method_len, method, uri_len, uri);
    }

    TSIOBufferWrite(fch->req_buffer, buf, n);
}
Example #12
0
static int
ts_lua_say(lua_State * L)
{
  const char *data;
  size_t len;

  ts_lua_http_intercept_ctx *ictx;

  ictx = ts_lua_get_http_intercept_ctx(L);

  data = luaL_checklstring(L, 1, &len);

  if (len > 0) {
    TSIOBufferWrite(ictx->output.buffer, data, len);
    TSVIOReenable(ictx->output.vio);
  }

  return 0;
}
Example #13
0
static int
add_file_to_resp(AcmeState *my_state)
{
  if (-1 == my_state->fd) {
    return add_data_to_resp("\r\n", 2, my_state);
  } else {
    int ret = 0, len;
    char buf[8192];

    while (1) {
      len = read(my_state->fd, buf, sizeof(buf));
      if ((0 == len) || ((-1 == len) && (errno != EAGAIN) && (errno != EINTR))) {
        break;
      } else {
        TSIOBufferWrite(my_state->resp_buffer, buf, len);
        ret += len;
      }
    }
    close(my_state->fd);
    my_state->fd = -1;

    return ret;
  }
}
/* Add data to the output */
inline static int
add_data_to_resp(const char *buf, int len, HCState *my_state)
{
  TSIOBufferWrite(my_state->resp_buffer, buf, len);
  return len;
}
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;
}
static int
ts_lua_transform_handler(TSCont contp, ts_lua_transform_ctx *transform_ctx)
{
    TSVConn             output_conn;
    TSVIO               input_vio;
    TSIOBufferReader    input_reader;
    TSIOBufferBlock     blk;
    int64_t             towrite, blk_len, upstream_done, avail, left;
    const char          *start;
    const char          *res;
    size_t              res_len;
    int                 ret, eos;

    lua_State           *L;
    TSMutex             mtxp;

    L = transform_ctx->hctx->lua;
    mtxp = transform_ctx->hctx->mctx->mutexp;

    output_conn = TSTransformOutputVConnGet(contp);
    input_vio = TSVConnWriteVIOGet(contp);
    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->output_vio = TSVConnWrite(output_conn, contp, transform_ctx->output_reader, INT64_MAX);
    }

    if (!TSVIOBufferGet(input_vio)) {
        TSVIONBytesSet(transform_ctx->output_vio, transform_ctx->total);
        TSVIOReenable(transform_ctx->output_vio);
        return 1;
    }

    if (transform_ctx->eos) {
        return 1;
    }

    left = towrite = TSVIONTodoGet(input_vio);
    upstream_done = TSVIONDoneGet(input_vio);
    avail = TSIOBufferReaderAvail(input_reader);
    eos = 0;

    if (left <= avail)
        eos = 1;

    if (towrite > avail)
        towrite = avail;

    TSMutexLock(mtxp);

    blk = TSIOBufferReaderStart(input_reader);

    do {
        start = TSIOBufferBlockReadStart(blk, input_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;
        } else {
            lua_pushlstring(L, start, (size_t)towrite);
            towrite = 0;
        }

        if (!towrite && eos) {
            lua_pushinteger(L, 1);                          /* second param, not finish */ 
        } else {
            lua_pushinteger(L, 0);                          /* second param, not finish */ 
        }

        if (lua_pcall(L, 2, 2, 0)) {
            fprintf(stderr, "lua_pcall failed: %s\n", lua_tostring(L, -1));
        }

        ret = lua_tointeger(L, -1);                         /* 0 is not finished, 1 is finished */
        res = lua_tolstring(L, -2, &res_len);

        if (res && res_len) {
            TSIOBufferWrite(transform_ctx->output_buffer, res, res_len);
            transform_ctx->total += res_len;
        }

        lua_pop(L, 2);

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

        blk = TSIOBufferBlockNext(blk);

    } while (blk && towrite > 0);

    TSMutexUnlock(mtxp);

    TSIOBufferReaderConsume(input_reader, avail);
    TSVIONDoneSet(input_vio, upstream_done + avail);

    if (eos) {
        transform_ctx->eos = 1;
        TSVIONBytesSet(transform_ctx->output_vio, transform_ctx->total);
        TSVIOReenable(transform_ctx->output_vio);
        TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_COMPLETE, input_vio);
    } else {
        TSVIOReenable(transform_ctx->output_vio);
        TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_READY, input_vio);
    }

    return 1;
}
Example #17
0
static int
ts_lua_cache_write(lua_State *L)
{
    int64_t                 length, n;
    const char              *data;
    size_t                  dlen;
    ts_lua_cont_info        *ci;
    ts_lua_cache_info       *info;

    ci = ts_lua_get_cont_info(L);
    if (ci == NULL)
        return 0;

    n = lua_gettop(L);
    if (n < 2) {
        return luaL_error(L, "'ts.cache_write' requires parameter");
    }

    /* data */
    if (!lua_isstring(L, 2)) {
        return luaL_error(L, "'ts.cache_write' second param is not string");
    }

    data = luaL_checklstring(L, 2, &dlen);

    /* length */
    length = dlen;

    if (n >= 3) {
        if (!lua_isnumber(L, 3)) {
            return luaL_error(L, "'ts.cache_write' third param is not number");
        }

        length = lua_tonumber(L, 3);
        if (length <= 0) {
            return luaL_error(L, "'ts.cache_write' third param is a not valid number");
        }

        if (length > dlen)
            length = dlen;
    }

    /* table */
    if (!lua_istable(L, 1)) {
        return luaL_error(L, "'ts.cache_write' first param is not valid");
    }

    lua_pushlstring(L, "info", sizeof("info") - 1);
    lua_gettable(L, 1);

    if (!lua_islightuserdata(L, -1)) {
        return luaL_error(L, "'ts.cache_write' first param is not valid");
    }

    info = (ts_lua_cache_info*)lua_touserdata(L, -1);
    lua_pop(L, 1);

    if (info->optype != TS_LUA_CACHE_WRITE) {
        return luaL_error(L, "'ts.cache_write' is writing to invalid vc");
    }

    if (info->err) {
        lua_pushnil(L);
        return 1;
    }

    info->need += length;
    info->current_handler = &ts_lua_cache_handle_write;
    TSIOBufferWrite(info->ioh.buffer, data, length);

    if (info->ioh.vio == NULL) {
        info->ioh.vio = TSVConnWrite(info->cache_vc, info->contp, info->ioh.reader, INT64_MAX);

    } else {
        TSVIOReenable(info->ioh.vio);
    }

    info->wait = 1;
    return lua_yield(L, 0);
}
Example #18
0
/**
 * Function to flush buffered data and apply edits in-stream
 *
 * @param[in] fctx - the filter data
 * @param[in] nbytes - number of bytes to flush (-1 to flush all data)
 * @param[in] last - final flush indicator (no more data to come)
 * @return success or error status
 */
static ib_status_t flush_data(tsib_filter_ctx *fctx, int64_t nbytes, int last)
{
    /* copy logic from mod_range_filter.
     *
     *
     * It's a push logic, so that'll be range_filter's output filter
     *
     * Note: We're not buffering anything here.  We only see data
     *       when they're flushed from the buffer!
     */
    ib_status_t rc = IB_OK;
    int nedits, i;
    size_t n, start;
    if (nbytes == -1) {
        /* just output all we have */
        nbytes = fctx->buffered;
    }

    if ((fctx->edits != NULL) && (fctx->edits->len > 0)) {
        /* Sort to reverse order, so we can pop elements simply by
         * decrementing len
         */
        nedits = fctx->edits->len/sizeof(edit_t);
        qsort(fctx->edits->data, nedits, sizeof(edit_t), qcompare);
        for (i = nedits-1; i >= 0; --i) {
            edit_t *edit = &((edit_t*) fctx->edits->data)[i];

            /* sanity-check that edit is in range */
            if (edit->start < fctx->bytes_done) {
                /* Edit applies to data already gone.  This probably means
                 * someone fed us overlapping edits
                 */
                rc = IB_EBADVAL;

                /* Abandon this edit.  Continue loop (next edit may be fine) */
                fctx->edits->len -= sizeof(edit_t);
                continue;
            }
            else if (edit->start + edit->bytes > fctx->bytes_done + nbytes) {
                /* Edit goes beyond data we're dealing with.
                 * So leave it for next time.
                 * This could affect buffering behaviour, but in a good cause
                 * If this is out-of-range then so are other edits,
                 * but they'll be in range when we have more data.
                 *
                 * Best we can do now is to flush data before this edit.
                 * by setting nbytes.
                 *
                 * Exception: if it's the last call, this edit is out-of-range
                 * so we just abandon it.
                 */
                if (!last) {
                    nbytes = edit->start - fctx->bytes_done;
                    rc = IB_EAGAIN;
                    break;
                }
                else {
                    fctx->edits->len -= sizeof(edit_t);
                    rc = IB_EBADVAL;
                    continue;
                }
            }

            /* copy data up to start-of-edit */
            start = edit->start - fctx->bytes_done;
            while (start > 0) {
                n = TSIOBufferCopy(fctx->output_buffer, fctx->reader, start, 0);
                assert (n > 0);  // FIXME - handle error
                TSIOBufferReaderConsume(fctx->reader, n);
                fctx->buffered -= n;
                fctx->bytes_done += n;
                nbytes -= n;
                start -= n;
            }

            /* Discard anything that's being deleted */
            TSIOBufferReaderConsume(fctx->reader, edit->bytes);
            nbytes -= edit->bytes;
            fctx->buffered -= edit->bytes;
            fctx->bytes_done += edit->bytes;

            /* Insert replacement string */
            n = TSIOBufferWrite(fctx->output_buffer, edit->repl, edit->repl_len);
            assert(n == edit->repl_len);  // FIXME (if this ever happens)!

            /* Record change to data size */
            fctx->offs += edit->repl_len - edit->bytes;

            /* We're done with this edit. */
            fctx->edits->len -= sizeof(edit_t);
        }
    }

    /* There's no (more) editing to do, so we can just move data to output
     * using TS native refcounted pointer ops
     */
    while (nbytes > 0) {
        n = TSIOBufferCopy(fctx->output_buffer, fctx->reader, nbytes, 0);
        assert (n > 0);  // FIXME - handle error
        TSIOBufferReaderConsume(fctx->reader, n);
        fctx->buffered -= n;
        fctx->bytes_done += n;
        nbytes -= n;
    }
    if (last) {
        // TODO - Do we need to add this to what is there vs just set it as we are now?
        /* Now we can tell downstream exactly how much data it has */
        TSVIONBytesSet(fctx->output_vio, fctx->bytes_done + fctx->offs);
    }
    TSVIOReenable(fctx->output_vio);
    return rc;
}