Ejemplo n.º 1
0
/*-------------------------------------------------------------------------
  wake_up_streams
  Send an event to the upstream vconnection to either
    - ask for more data
    - let it know we're done
  Reenable the downstream vconnection
  Input:
    contp      continuation for the current transaction
  Output :
  Return Value:
   0 if failure
   1 if success
  -------------------------------------------------------------------------*/
static int
wake_up_streams(TSCont contp)
{
  TSVIO input_vio;
  ContData *data;
  int ntodo;

  data = TSContDataGet(contp);
  TSAssert(data->magic == MAGIC_ALIVE);

  input_vio = TSVConnWriteVIOGet(contp);
  ntodo = TSVIONTodoGet(input_vio);

  if (ntodo > 0) {
    TSVIOReenable(data->output_vio);
    TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_READY, input_vio);
  } else {
    TSDebug(DBG_TAG, "Total bytes produced by transform = %d", data->transform_bytes);
    TSVIONBytesSet(data->output_vio, data->transform_bytes);
    TSVIOReenable(data->output_vio);
    TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_COMPLETE, input_vio);
  }

  return 1;
}
Ejemplo n.º 2
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);
}
Ejemplo n.º 3
0
void
ts_http_fetcher_copy_data(http_fetcher *fch, TSIOBufferReader readerp, int64_t length, int64_t offset)
{
    TSIOBufferCopy(fch->req_buffer, readerp, length, offset);

    if (fch->launched)
        TSVIOReenable(fch->write_vio);
}
Ejemplo n.º 4
0
static int
transform_read_event(TSCont contp, TransformData * data, TSEvent event, void *edata)
{
  switch (event) {
  case TS_EVENT_ERROR:
    TSVConnAbort(data->server_vc, 1);
    data->server_vc = NULL;
    data->server_vio = NULL;

    TSVConnAbort(data->output_vc, 1);
    data->output_vc = NULL;
    data->output_vio = NULL;
    break;
  case TS_EVENT_VCONN_EOS:
    TSVConnAbort(data->server_vc, 1);
    data->server_vc = NULL;
    data->server_vio = NULL;

    TSVConnAbort(data->output_vc, 1);
    data->output_vc = NULL;
    data->output_vio = NULL;
    break;
  case TS_EVENT_VCONN_READ_COMPLETE:
    TSVConnClose(data->server_vc);
    data->server_vc = NULL;
    data->server_vio = NULL;

    TSVIOReenable(data->output_vio);
    break;
  case TS_EVENT_VCONN_READ_READY:
    TSVIOReenable(data->output_vio);
    break;
  case TS_EVENT_VCONN_WRITE_COMPLETE:
    TSVConnShutdown(data->output_vc, 0, 1);
    break;
  case TS_EVENT_VCONN_WRITE_READY:
    TSVIOReenable(data->server_vio);
    break;
  default:
    break;
  }

  return 0;
}
Ejemplo n.º 5
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);
}
static int
ts_lua_http_intercept_process_write(TSEvent event, ts_lua_http_intercept_ctx *ictx)
{
  int64_t done, avail;

  switch (event) {
  case TS_EVENT_VCONN_WRITE_READY:

    avail = TSIOBufferReaderAvail(ictx->output.reader);

    if (ictx->all_ready) {
      TSVIOReenable(ictx->output.vio);

    } else if (ictx->to_flush > 0) { // ts.flush()

      done = TSVIONDoneGet(ictx->output.vio);

      if (ictx->to_flush > done) {
        TSVIOReenable(ictx->output.vio);

      } else { // we had flush all the data we want
        ictx->to_flush = 0;
        ts_lua_flush_launch(ictx); // wake up
      }

    } else if (avail > 0) {
      TSVIOReenable(ictx->output.vio);
    }
    break;

  case TS_EVENT_VCONN_WRITE_COMPLETE:
    ictx->send_complete = 1;
    break;

  case TS_EVENT_ERROR:
  default:
    return -1;
  }

  return 0;
}
Ejemplo n.º 7
0
static int
transform_write_event(TSCont contp, TransformData * data, TSEvent event, void *edata)
{
  switch (event) {
  case TS_EVENT_VCONN_WRITE_READY:
    TSVIOReenable(data->server_vio);
    break;
  case TS_EVENT_VCONN_WRITE_COMPLETE:
    return transform_read_status(contp, data);
  case TS_EVENT_ERROR:
    return transform_bypass(contp, data);
  case TS_EVENT_IMMEDIATE:
    TSVIOReenable(data->server_vio);
    break;
  default:
    /* An error occurred while writing to the server. Close down
       the connection to the server and bypass. */
    return transform_bypass(contp, data);
  }

  return 0;
}
Ejemplo n.º 8
0
static int
ts_lua_cache_handle_write(ts_lua_cont_info *ci, ts_lua_cache_info *info, TSEvent event, void *edata)
{
    lua_State               *L;
    TSMutex                 mtx;
    int64_t                 avail, done, n;

    n = 0;

    switch (event) {

        case TS_EVENT_VCONN_WRITE_READY:
            done = TSVIONDoneGet(info->ioh.vio);
            if (done < info->need) {
                TSVIOReenable(info->ioh.vio);

            } else {
                n = info->need - info->already;
                avail = TSIOBufferReaderAvail(info->ioh.reader);
                TSIOBufferReaderConsume(info->ioh.reader, avail);
            }

            break;

        default:
            info->err = 1;
            break;
    }

    if (info->wait && (n > 0 || info->err)) {           // resume
        L = ci->routine.lua;
        mtx = ci->routine.mctx->mutexp;

        TSMutexLock(mtx);

        if (n > 0) {
            lua_pushnumber(L, n);
            info->already = info->need;

        } else {
            lua_pushnumber(L, 0);
        }

        info->wait = 0;
        TSContCall(ci->contp, TS_LUA_EVENT_COROUTINE_CONT, (void*)1);
        TSMutexUnlock(mtx);
    }

    return 0;
}
Ejemplo n.º 9
0
static int
transform_bypass_event(TSCont contp, TransformData * data, TSEvent event, void *edata)
{
  switch (event) {
  case TS_EVENT_VCONN_WRITE_COMPLETE:
    TSVConnShutdown(data->output_vc, 0, 1);
    break;
  case TS_EVENT_VCONN_WRITE_READY:
  default:
    TSVIOReenable(data->output_vio);
    break;
  }

  return 0;
}
Ejemplo n.º 10
0
static int
ts_lua_flush(lua_State * L)
{
  int64_t avail;
  ts_lua_http_intercept_ctx *ictx;

  ictx = ts_lua_get_http_intercept_ctx(L);
  avail = TSIOBufferReaderAvail(ictx->output.reader);

  if (avail > 0) {
    ictx->to_flush = TSVIONDoneGet(ictx->output.vio) + TSIOBufferReaderAvail(ictx->output.reader);
    TSVIOReenable(ictx->output.vio);

    return lua_yield(L, 0);
  }

  return 0;
}
Ejemplo n.º 11
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;
}
Ejemplo n.º 12
0
int
ts_http_fetcher_process_write(http_fetcher *fch, TSEvent event)
{
    switch (event) {

        case TS_EVENT_VCONN_WRITE_READY:
            TSVIOReenable(fch->write_vio);
            break;

        case TS_EVENT_VCONN_WRITE_COMPLETE:
            break;

        case TS_EVENT_ERROR:
        default:
            return ts_http_fetcher_callback_sm(fch, TS_FETCH_EVENT_ERROR);
    }

    return 0;
}
Ejemplo n.º 13
0
static void
stats_process_write(TSCont contp, TSEvent event, stats_state * my_state)
{
  if (event == TS_EVENT_VCONN_WRITE_READY) {
    if (my_state->body_written == 0) {
      TSDebug("istats", "plugin adding response body");
      my_state->body_written = 1;
      json_out_stats(my_state);
      TSVIONBytesSet(my_state->write_vio, my_state->output_bytes);
    }
    TSVIOReenable(my_state->write_vio);
  } else if (TS_EVENT_VCONN_WRITE_COMPLETE) {
    stats_cleanup(contp, my_state);
  } else if (event == TS_EVENT_ERROR) {
    TSError("stats_process_write: Received TS_EVENT_ERROR\n");
  } else {
    TSReleaseAssert(!"Unexpected Event");
  }
}
static int
ts_lua_http_intercept_process_write(TSEvent event, ts_lua_http_intercept_ctx * ictx)
{
  switch (event) {
  case TS_EVENT_VCONN_WRITE_READY:
    if (TSIOBufferReaderAvail(ictx->output.reader))
      TSVIOReenable(ictx->output.vio);
    break;

  case TS_EVENT_VCONN_WRITE_COMPLETE:
    ictx->send_complete = 1;
    break;

  case TS_EVENT_ERROR:
  default:
    return -1;
  }

  return 0;
}
Ejemplo n.º 15
0
/* Process a write event from the SM */
static void
acme_process_write(TSCont contp, TSEvent event, AcmeState *my_state)
{
  if (event == TS_EVENT_VCONN_WRITE_READY) {
    char buf[64]; /* Plenty of space for CL: header */
    int len;

    len = snprintf(buf, sizeof(buf) - 1, "Content-Length: %zd\r\n\r\n", my_state->stat_buf.st_size);
    my_state->output_bytes += add_data_to_resp(buf, len, my_state);
    my_state->output_bytes += add_file_to_resp(my_state);

    TSVIONBytesSet(my_state->write_vio, my_state->output_bytes);
    TSVIOReenable(my_state->write_vio);
  } else if (TS_EVENT_VCONN_WRITE_COMPLETE) {
    cleanup(contp, my_state);
  } else if (event == TS_EVENT_ERROR) {
    TSError("[%s] acme_process_write: Received TS_EVENT_ERROR", PLUGIN_NAME);
  } else {
    TSReleaseAssert(!"Unexpected Event");
  }
}
static int
ts_lua_http_intercept_run_coroutine(ts_lua_http_intercept_ctx * ictx, int n)
{
  int ret;
  int64_t avail;
  int64_t done;
  lua_State *L;

  L = ictx->lua;

  ret = lua_resume(L, n);

  switch (ret) {

  case 0:                      // finished
    avail = TSIOBufferReaderAvail(ictx->output.reader);
    done = TSVIONDoneGet(ictx->output.vio);
    TSVIONBytesSet(ictx->output.vio, avail + done);
    ictx->all_ready = 1;

    if (avail) {
      TSVIOReenable(ictx->output.vio);

    } else {
      ictx->send_complete = 1;
    }
    break;

  case 1:                      // yield
    break;

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

  return 0;
}
/* Process a write event from the SM */
static void
hc_process_write(TSCont contp, TSEvent event, HCState *my_state)
{
  if (event == TS_EVENT_VCONN_WRITE_READY) {
    char buf[48];
    int len;

    len = snprintf(buf, sizeof(buf)-1, "Content-Length: %d\r\n\r\n", my_state->data->b_len);
    my_state->output_bytes += add_data_to_resp(buf, len, my_state);
    if (my_state->data->b_len > 0)
      my_state->output_bytes += add_data_to_resp(my_state->data->body, my_state->data->b_len, my_state);
    else
      my_state->output_bytes += add_data_to_resp("\r\n", 2, my_state);
    TSVIONBytesSet(my_state->write_vio, my_state->output_bytes);
    TSVIOReenable(my_state->write_vio);
  } else if (TS_EVENT_VCONN_WRITE_COMPLETE) {
    cleanup(contp, my_state);
  } else if (event == TS_EVENT_ERROR) {
    TSError("hc_process_write: Received TS_EVENT_ERROR\n");
  } else {
    TSReleaseAssert(!"Unexpected Event");
  }
}
Ejemplo n.º 18
0
/*-------------------------------------------------------------------------
  dump_psi
  Dump the psi_output to the downstream vconnection.

  Input:
    contp      continuation for the current transaction
  Output :
  Return Value:
   0 if failure
   1 if success
  -------------------------------------------------------------------------*/
static int
dump_psi(TSCont contp)
{
  ContData *data;
  int psi_output_len;

  /* TODO: This is odd, do we need to get the input_vio, but never use it ?? */
#if 0
  TSVIO input_vio;
  input_vio = TSVConnWriteVIOGet(contp);
#endif

  data = TSContDataGet(contp);
  TSAssert(data->magic == MAGIC_ALIVE);

  /* If script exec succeded, copy its output to the downstream vconn */
  if (data->psi_success == 1) {
    psi_output_len = TSIOBufferReaderAvail(data->psi_reader);

    if (psi_output_len > 0) {
      data->transform_bytes += psi_output_len;

      TSDebug(DBG_TAG, "Inserting %d bytes from include file", psi_output_len);
      /* TODO: Should we check the return value of TSIOBufferCopy() ? */
      TSIOBufferCopy(TSVIOBufferGet(data->output_vio), data->psi_reader, psi_output_len, 0);
      /* Consume all the output data */
      TSIOBufferReaderConsume(data->psi_reader, psi_output_len);

      /* Reenable the output connection so it can read the data we've produced. */
      TSVIOReenable(data->output_vio);
    }
  }

  /* Change state to finish up reading upstream data */
  data->state = STATE_READ_DATA;
  return 0;
}
Ejemplo n.º 19
0
static int
ts_lua_cache_read(lua_State *L)
{
    int64_t                 length, n, avail;
    char                    *dst;
    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 < 1) {
        return luaL_error(L, "'ts.cache_read' requires parameter");
    }

    /* length */
    if (n >= 2) {
        if (!lua_isnumber(L, 2)) {
            return luaL_error(L, "'ts.cache_read' second param is not number");
        }

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

    } else {
        length = INT64_MAX;
    }

    /* table */
    if (!lua_istable(L, 1)) {
        return luaL_error(L, "'ts.cache_read' 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_read' first param is not valid");
    }

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

    if (info->hit == 0) {
        return luaL_error(L, "'ts.cache_read' is reading from unhit doc");
    }

    if (info->optype != TS_LUA_CACHE_READ) {
        return luaL_error(L, "'ts.cache_read' is reading from invalid vc");
    }

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

    if (length != INT64_MAX) {
        info->need += length;

    } else {
        info->need = INT64_MAX;
    }

    info->current_handler = &ts_lua_cache_handle_read;

    avail = TSIOBufferReaderAvail(info->reserved.reader);
    if (avail + info->already >= info->need) {
        n = info->need - info->already;

        dst = (char*)TSmalloc(n);
        IOBufferReaderCopy(info->reserved.reader, dst, n);
        lua_pushlstring(L, (char*)dst, n);
        TSfree(dst);

        info->already = info->need;
        TSIOBufferReaderConsume(info->reserved.reader, n);
        return 1;
    }

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

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

    info->wait = 1;
    return lua_yield(L, 0);
}
Ejemplo n.º 20
0
static int
ts_dechunk_transform_handler(TSCont contp, ts_dechunk_transform_ctx *tc)
{
    TSVConn             output_conn;
    TSVIO               input_vio;
    TSIOBufferReader    input_reader;
    int64_t             towrite, upstream_done, avail;
    int                 ret, eos;

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

    if (!tc->output_buffer) {
        tc->output_buffer = TSIOBufferCreate();
        tc->output_reader = TSIOBufferReaderAlloc(tc->output_buffer);
        tc->output_vio = TSVConnWrite(output_conn, contp, tc->output_reader, INT64_MAX);
    }

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

    towrite = TSVIONTodoGet(input_vio);
    upstream_done = TSVIONDoneGet(input_vio);

    avail = TSIOBufferReaderAvail(input_reader);

    if (towrite > avail) {
        towrite = avail;
        eos = 0;

    } else {
        eos = 1;
    }

    ret = ts_dechunk_process(tc->info, input_reader, tc->output_buffer, eos);

    if (ret < 0) {
        tc->total = TSVIONDoneGet(tc->output_vio) + TSIOBufferReaderAvail(tc->output_reader);
        TSVIONBytesSet(tc->output_vio, tc->total);
        TSVIOReenable(tc->output_vio);
        TSContCall(TSVIOContGet(input_vio), TS_EVENT_ERROR, input_vio);
        return ret;
    }

    if (!ret) {
        TSVIOReenable(tc->output_vio);
        TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_READY, input_vio);

    } else {

        tc->total = TSVIONDoneGet(tc->output_vio) + TSIOBufferReaderAvail(tc->output_reader);
        TSVIONBytesSet(tc->output_vio, tc->total);
        TSVIOReenable(tc->output_vio);
        TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_COMPLETE, input_vio);
    }

    return 1;
}
Ejemplo n.º 21
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;
}
Ejemplo n.º 22
0
int
ts_http_fetcher_filter_body(http_fetcher *fch, int ev)
{
    int         ret;
    int64_t     resp_avail, body_avail, wavail, need;

    if (fch->action) {
        TSActionCancel(fch->action);
        fch->action = NULL;
    }

    need = 0;
    resp_avail = TSIOBufferReaderAvail(fch->resp_reader);

    if (ev != BODY_COMPLETE) {

        body_avail = TSIOBufferReaderAvail(fch->body_reader);
        wavail = TS_FETCH_MARK_BODY_HIGH_WATER - body_avail;

        if (wavail <= 0)
            return TS_FETCH_EVENT_BODY_QUIET;

        need = resp_avail > wavail ? wavail : resp_avail;

        TSIOBufferCopy(fch->flow_buffer, fch->resp_reader, need, 0);
        TSIOBufferReaderConsume(fch->resp_reader, need);

        if (TSIOBufferReaderAvail(fch->resp_reader) < TS_FETCH_MARK_RESP_LOW_WATER)
            TSVIOReenable(fch->read_vio);

    } else  {
        TSIOBufferCopy(fch->flow_buffer, fch->resp_reader, resp_avail, 0);
        TSIOBufferReaderConsume(fch->resp_reader, resp_avail);
        need = resp_avail;
    }

    if (fch->chunked) {
        ret = ts_http_fetcher_verify_chunked(fch, ev);

    } else if (fch->resp_cl >= 0) {
        ret = ts_http_fetcher_verify_cl(fch, ev);

    } else {
        ret = ts_http_fetcher_transfer(fch, ev);
    }

    switch (ret) {

        case BODY_READY:
            if (need == 0)
                return TS_FETCH_EVENT_BODY_QUIET;

            return TS_FETCH_EVENT_BODY_READY;

        case BODY_COMPLETE:
            fch->body_done = 1;
            return TS_FETCH_EVENT_BODY_COMPLETE;

        default:
            break;
    }

    fch->error = 1;
    return TS_FETCH_EVENT_ERROR;
}
Ejemplo n.º 23
0
int
ts_http_fetcher_process_read(http_fetcher *fch, TSEvent event)
{
    int         ret;

    switch (event) {

        case TS_EVENT_VCONN_READ_READY:
        case TS_EVENT_VCONN_READ_COMPLETE:
        case TS_EVENT_VCONN_EOS:

            if (!fch->header_done) {
                ret = ts_http_fetcher_parse_header(fch);
                if (ret) {
                    return ts_http_fetcher_callback_sm(fch, TS_FETCH_EVENT_ERROR);

                } else if (fch->header_done) {
                    if (!(fch->flags & TS_FETCH_FLAG_IGNORE_HEADER_DONE)) {
                        ret = ts_http_fetcher_callback_sm(fch, TS_FETCH_EVENT_HEADER_DONE);
                        if (ret)
                            return -1;
                    }
                }
            }

            if (event == TS_EVENT_VCONN_READ_READY) {

                if (fch->header_done) {

                    if (fch->status_code == TS_HTTP_STATUS_NOT_MODIFIED || fch->status_code == TS_HTTP_STATUS_NO_CONTENT) {
                        ret = ts_http_fetcher_filter_body(fch, BODY_COMPLETE);
                    } else {
                        ret = ts_http_fetcher_filter_body(fch, BODY_READY);
                    }

                    if (ret != TS_FETCH_EVENT_BODY_READY || !(fch->flags & TS_FETCH_FLAG_IGNORE_BODY_READY)) {
                        if (ts_http_fetcher_callback_sm(fch, ret))
                            return -1;
                    }

                } else {
                    TSVIOReenable(fch->read_vio);
                }

            } else if (fch->header_done) {
                ret = ts_http_fetcher_filter_body(fch, BODY_COMPLETE);
                return ts_http_fetcher_callback_sm(fch, ret);

            } else {
                return ts_http_fetcher_callback_sm(fch, TS_FETCH_EVENT_ERROR);
            }

            break;

        case TS_EVENT_ERROR:
        default:
            return ts_http_fetcher_callback_sm(fch, TS_FETCH_EVENT_ERROR);
    }

    return 0;
}
static void
handle_transform(TSCont contp)
{
  TSVConn output_conn;
  TSVIO write_vio;
  MyData *data;
  int64_t towrite;

  /* Get the output connection where we'll write data to. */
  output_conn = TSTransformOutputVConnGet(contp);

  /* 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);

  /* Get our data structure for this operation. The private data
     structure contains the output VIO and output buffer. If the
     private data structure pointer is NULL, then we'll create it
     and initialize its internals. */
  data = TSContDataGet(contp);
  if (!data) {
    towrite = TSVIONBytesGet(write_vio);
    if (towrite != INT64_MAX) {
      towrite += append_buffer_length;
    }
    data                = my_data_alloc();
    data->output_buffer = TSIOBufferCreate();
    data->output_reader = TSIOBufferReaderAlloc(data->output_buffer);
    data->output_vio    = TSVConnWrite(output_conn, contp, data->output_reader, towrite);
    TSContDataSet(contp, data);
  }

  /* 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 simplistic
     transformation that means we're done. In a more complex
     transformation we might have to finish writing the transformed
     data to our output connection. */
  if (!TSVIOBufferGet(write_vio)) {
    if (data->append_needed) {
      data->append_needed = 0;
      TSIOBufferCopy(TSVIOBufferGet(data->output_vio), append_buffer_reader, append_buffer_length, 0);
    }

    TSVIONBytesSet(data->output_vio, TSVIONDoneGet(write_vio) + append_buffer_length);
    TSVIOReenable(data->output_vio);

    return;
  }

  /* Determine how much data we have left to read. For this append
     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. */
    int64_t avail = TSIOBufferReaderAvail(TSVIOReaderGet(write_vio));
    if (towrite > avail) {
      towrite = avail;
    }

    if (towrite > 0) {
      /* Copy the data from the read buffer to the output buffer. */
      TSIOBufferCopy(TSVIOBufferGet(data->output_vio), 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) {
      /* If there is data left to read, then we reenable the output
         connection by reenabling the output VIO. This will wakeup
         the output connection and allow it to consume data from the
         output buffer. */
      TSVIOReenable(data->output_vio);

      /* 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 {
    if (data->append_needed) {
      data->append_needed = 0;
      TSIOBufferCopy(TSVIOBufferGet(data->output_vio), append_buffer_reader, append_buffer_length, 0);
    }

    /* If there is no data left to read, then we modify the output
       VIO to reflect how much data the output connection should
       expect. This allows the output connection to know when it
       is done reading. We then reenable the output connection so
       that it can consume the data we just gave it. */
    TSVIONBytesSet(data->output_vio, TSVIONDoneGet(write_vio) + append_buffer_length);
    TSVIOReenable(data->output_vio);

    /* 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);
  }
}
Ejemplo n.º 25
0
static void
handle_transform(TSCont contp)
{
  TSVConn output_conn;
  TSIOBuffer buf_test;
  TSVIO input_vio;
  MyData *data;
  int64_t towrite;
  int64_t avail;

  TSDebug("null-transform", "Entering handle_transform()");
  /* Get the output (downstream) vconnection where we'll write data to. */

  output_conn = TSTransformOutputVConnGet(contp);

  /* 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. This is the input VIO (the write VIO for the upstream
   * vconnection).
   */
  input_vio = TSVConnWriteVIOGet(contp);

  /* Get our data structure for this operation. The private data
   * structure contains the output VIO and output buffer. If the
   * private data structure pointer is NULL, then we'll create it
   * and initialize its internals.
   */
  data = TSContDataGet(contp);
  if (!data) {
    data = my_data_alloc();
    data->output_buffer = TSIOBufferCreate();
    data->output_reader = TSIOBufferReaderAlloc(data->output_buffer);
    TSDebug("null-transform", "\tWriting %" PRId64 " bytes on VConn", TSVIONBytesGet(input_vio));
    // data->output_vio = TSVConnWrite(output_conn, contp, data->output_reader, INT32_MAX);
    data->output_vio = TSVConnWrite(output_conn, contp, data->output_reader, INT64_MAX);
    // data->output_vio = TSVConnWrite(output_conn, contp, data->output_reader, TSVIONBytesGet(input_vio));
    TSContDataSet(contp, data);
  }

  /* We also check to see if the input VIO's buffer is non-NULL. A
   * NULL buffer indicates that the write operation has been
   * shutdown and that the upstream continuation does not want us to send any
   * more WRITE_READY or WRITE_COMPLETE events. For this simplistic
   * transformation that means we're done. In a more complex
   * transformation we might have to finish writing the transformed
   * data to our output connection.
   */
  buf_test = TSVIOBufferGet(input_vio);

  if (!buf_test) {
    TSVIONBytesSet(data->output_vio, TSVIONDoneGet(input_vio));
    TSVIOReenable(data->output_vio);
    return;
  }

  /* Determine how much data we have left to read. For this null
   * transform plugin this is also the amount of data we have left
   * to write to the output connection.
   */
  towrite = TSVIONTodoGet(input_vio);
  TSDebug("null-transform", "\ttoWrite is %" PRId64 "", towrite);

  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(input_vio));
    TSDebug("null-transform", "\tavail is %" PRId64 "", avail);
    if (towrite > avail) {
      towrite = avail;
    }

    if (towrite > 0) {
      /* Copy the data from the read buffer to the output buffer. */
      TSIOBufferCopy(TSVIOBufferGet(data->output_vio), TSVIOReaderGet(input_vio), towrite, 0);

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

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

  /* Now we check the input VIO to see if there is data left to
   * read.
   */
  if (TSVIONTodoGet(input_vio) > 0) {
    if (towrite > 0) {
      /* If there is data left to read, then we reenable the output
       * connection by reenabling the output VIO. This will wake up
       * the output connection and allow it to consume data from the
       * output buffer.
       */
      TSVIOReenable(data->output_vio);

      /* Call back the input VIO continuation to let it know that we
       * are ready for more data.
       */
      TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_READY, input_vio);
    }
  } else {
    /* If there is no data left to read, then we modify the output
     * VIO to reflect how much data the output connection should
     * expect. This allows the output connection to know when it
     * is done reading. We then reenable the output connection so
     * that it can consume the data we just gave it.
     */
    TSVIONBytesSet(data->output_vio, TSVIONDoneGet(input_vio));
    TSVIOReenable(data->output_vio);

    /* Call back the input VIO continuation to let it know that we
     * have completed the write operation.
     */
    TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_COMPLETE, input_vio);
  }
}
Ejemplo n.º 26
0
/*-------------------------------------------------------------------------
  handle_transform
   Get data from upstream vconn.
   Parse it.
   Include file if include tags found.
   Copy data to downstream vconn.
   Wake up upstream to get more data.

  Input:
    contp      continuation for the current transaction
  Output :
  Return Value:
   0 if failure
   1 if success
  -------------------------------------------------------------------------*/
static int
handle_transform(TSCont contp)
{
  TSVConn output_conn;
  TSVIO input_vio;
  ContData *data;
  TSIOBufferReader input_reader;
  int toread, avail, psi, toconsume, towrite;

  /* Get the output (downstream) vconnection where we'll write data to. */
  output_conn = TSTransformOutputVConnGet(contp);

  /* Get upstream vio */
  input_vio = TSVConnWriteVIOGet(contp);
  data = TSContDataGet(contp);
  TSAssert(data->magic == MAGIC_ALIVE);

  if (!data->output_buffer) {
    data->output_buffer = TSIOBufferCreate();
    data->output_reader = TSIOBufferReaderAlloc(data->output_buffer);

    /* INT64_MAX because we don't know yet how much bytes we'll produce */
    data->output_vio = TSVConnWrite(output_conn, contp, data->output_reader, INT64_MAX);
  }

  /* If the input VIO's buffer is NULL, the transformation is over */
  if (!TSVIOBufferGet(input_vio)) {
    TSDebug(DBG_TAG, "input_vio NULL, terminating transformation");
    TSVIONBytesSet(data->output_vio, data->transform_bytes);
    TSVIOReenable(data->output_vio);
    return 1;
  }

  /* Determine how much data we have left to read. */
  toread = TSVIONTodoGet(input_vio);

  if (toread > 0) {
    input_reader = TSVIOReaderGet(input_vio);
    avail = TSIOBufferReaderAvail(input_reader);

    /* There are some data available for reading. Let's parse it */
    if (avail > 0) {

      /* No need to parse data if there are too few bytes left to contain
         an include command... */
      if (toread > (PSI_START_TAG_LEN + PSI_END_TAG_LEN)) {
        psi = parse_data(contp, input_reader, avail, &toconsume, &towrite);
      } else {
        towrite = avail;
        toconsume = avail;
        psi = 0;
      }

      if (towrite > 0) {
        /* Update the total size of the doc so far */
        data->transform_bytes += towrite;

        /* Copy the data from the read buffer to the output buffer. */
        /* TODO: Should we check the return value of TSIOBufferCopy() ? */
        TSIOBufferCopy(TSVIOBufferGet(data->output_vio), TSVIOReaderGet(input_vio), towrite, 0);
        /* Reenable the output connection so it can read the data we've produced. */
        TSVIOReenable(data->output_vio);
      }

      if (toconsume > 0) {
        /* Consume data we've processed an we are no longer interested in */
        TSIOBufferReaderConsume(input_reader, toconsume);

        /* Modify the input VIO to reflect how much data we've completed. */
        TSVIONDoneSet(input_vio, TSVIONDoneGet(input_vio) + toconsume);
      }

      /* Did we find a psi filename to execute in the data ? */
      if (psi) {
        Job *new_job;
        /* Add a request to include a file into the jobs queue.. */
        /* We'll be called back once it's done with an EVENT_IMMEDIATE */
        TSDebug(DBG_TAG, "Psi filename extracted. Adding an include job to thread queue.");
        data->state = STATE_READ_PSI;

        /* Create a new job request and add it to the queue */
        new_job = job_create(contp, &psi_include, NULL);
        add_to_queue(&job_queue, new_job);

        /* Signal to the threads there is a new job */
        thread_signal_job();

        return 1;
      }
    }
  }

  /* Wake up upstream and downstream vconnections */
  wake_up_streams(contp);

  return 1;
}
Ejemplo n.º 27
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;
}
Ejemplo n.º 28
0
/**
 * Process data from ATS.
 *
 * Process data from one of the ATS events.
 *
 * @param[in,out] contp - the continuation
 * @param[in,out] ibd - the filter descriptor
 */
static void process_data(TSCont contp, ibd_ctx *ibd)
{
    int64_t ntodo;
    int64_t navail;
    TSIOBufferReader input_reader, output_reader;
    TSIOBufferBlock block;
    const char *buf;
    int64_t nbytes;
    ib_status_t rc;

    tsib_filter_ctx *fctx = ibd->data;

    tsib_txn_ctx *txndata = TSContDataGet(contp);
    TSVIO  input_vio = TSVConnWriteVIOGet(contp);
    TSIOBuffer in_buf = TSVIOBufferGet(input_vio);

    /* Test whether we're going into an errordoc */
    if (HTTP_CODE(txndata->status)) {  /* We're going to an error document,
                                        * so we discard all this data
                                        */
        ib_log_debug2_tx(txndata->tx, "Status is %d, discarding", txndata->status);
        ibd->data->buffering = IOBUF_DISCARD;
    }

    /* Test for EOS */
    if (in_buf == NULL) {
        if (fctx->output_buffer != NULL) {
            /* flush anything we have buffered.  This is final! */
            rc = flush_data(fctx, -1, 1);
            switch(rc) {
              case IB_OK:
                break;
              case IB_EBADVAL:
                ib_log_error_tx(txndata->tx, "Bad/Inconsistent stream edit(s) ignored.");
                break;
              default:  /* Can't happen unless a new status is introduced */
                ib_log_error_tx(txndata->tx, "Unhandled return value %d", rc);
                break;
            }
        }
        else {
            /* I guess NULL input may mean something other than EOS.
             * This appears to be possible when
             * processing an HTTP error from the backend.
             */
            ib_log_debug2_tx(txndata->tx, "Filter input was null.  No filtering.");
            /* RNS-1268: seems we may have to go through all the motions
             * of creating and enabling an output_vio with no data.
             */
            fctx->output_buffer = TSIOBufferCreate();
            ib_mm_register_cleanup(txndata->tx->mm,
                                   (ib_mm_cleanup_fn_t) TSIOBufferDestroy,
                                   (void*) fctx->output_buffer);
            output_reader = TSIOBufferReaderAlloc(fctx->output_buffer);
            fctx->output_vio = TSVConnWrite(TSTransformOutputVConnGet(contp), contp, output_reader, 0);
            TSVIOReenable(fctx->output_vio);
        }
        return;
    }

    /* Test for first time, and initialise.  */
    if (!fctx->output_buffer) {
        // FIXME - What to choose here and why?
        int64_t output_vio_sz = TSVIONBytesGet(input_vio);
        // NOTE: Using INT64_MAX asserts on 4.2.2: InkAPI.cc:6261: failed assert `sdk_sanity_check_iocore_structure(connp) == TS_SUCCESS`
        //int64_t output_vio_sz = INT64_MAX;
        // NOTE: Does it matter that this is only INT32_MAX as in the examples?
        // int64_t output_vio_sz = INT32_MAX;
        //int64_t output_vio_sz = fctx->have_edits
        //                        ? INT64_MAX
        //                        : TSVIONBytesGet(input_vio);
        fctx->output_buffer = TSIOBufferCreate();
        ib_mm_register_cleanup(txndata->tx->mm,
                               (ib_mm_cleanup_fn_t) TSIOBufferDestroy,
                               (void*) fctx->output_buffer);
        // FIXME - Where is TSIOBufferReaderFree()?
        output_reader = TSIOBufferReaderAlloc(fctx->output_buffer);
        fctx->output_vio = TSVConnWrite(TSTransformOutputVConnGet(contp), contp, output_reader, output_vio_sz);

        fctx->buffer = TSIOBufferCreate();
        ib_mm_register_cleanup(txndata->tx->mm,
                               (ib_mm_cleanup_fn_t) TSIOBufferDestroy,
                               (void*) fctx->buffer);
        // FIXME - Where is TSIOBufferReaderFree()?
        fctx->reader = TSIOBufferReaderAlloc(fctx->buffer);

        /* Get the buffering config */
        if (!HTTP_CODE(txndata->status)) {
            buffer_init(ibd, txndata->tx);
        }
    }

    /* Get any unprocessed bytes. */
    ntodo = TSVIONTodoGet(input_vio);

    /* Test for EOS */
    if (ntodo == 0) {
        ib_log_debug2_tx(txndata->tx, "ntodo zero before consuming data");

        flush_data(fctx, -1, 1);

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

    /* OK, there's some input awaiting our attention */
    input_reader = TSVIOReaderGet(input_vio);
    while (navail = TSIOBufferReaderAvail(input_reader), navail > 0) {
        block = TSIOBufferReaderStart(input_reader);
        buf = TSIOBufferBlockReadStart(block, input_reader, &nbytes);
        rc = (*ibd->ibd->ib_notify_body)(txndata->tx->ib, txndata->tx, buf, nbytes);
        if (rc != IB_OK) {
            ib_log_error_tx(txndata->tx, "Error %d notifying body data.", rc);
        }
        rc = buffer_data_chunk(fctx, input_reader, nbytes);
        switch (rc) {
          case IB_EAGAIN:
          case IB_OK:
            break;
          case IB_EBADVAL:
            ib_log_error_tx(txndata->tx, "Bad/Inconsistent stream edit(s) ignored.");
            break;
          default:  /* Can't happen unless a new status is introduced */
            ib_log_error_tx(txndata->tx, "Unhandled return value %d", rc);
            break;
        }
        TSIOBufferReaderConsume(input_reader, nbytes);
        TSVIONDoneSet(input_vio, TSVIONDoneGet(input_vio) + nbytes);
    }

    ntodo = TSVIONTodoGet(input_vio);
    if (ntodo == 0) {
        ib_log_debug2_tx(txndata->tx, "ntodo zero after consuming data");

        flush_data(fctx, -1, 1);

        /* Call back the input VIO continuation to let it know that we
         * have completed the write operation.
         */
        TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_COMPLETE, input_vio);
    }
    else {
        /* Call back the input VIO continuation to let it know that we
         * are ready for more data.
         */
        TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_READY, input_vio);
    }
}
Ejemplo n.º 29
0
static int
ts_lua_cache_handle_read(ts_lua_cont_info *ci, ts_lua_cache_info *info, TSEvent event, void *edata)
{
    lua_State               *L;
    TSMutex                 mtx;
    char                    *dst;
    int64_t                 avail, n;

    n = 0;

    switch (event) {

        case TS_EVENT_VCONN_READ_READY:
            avail = TSIOBufferReaderAvail(info->ioh.reader);
            if (avail > 0) {
                TSIOBufferCopy(info->reserved.buffer, info->ioh.reader, avail, 0);
                TSIOBufferReaderConsume(info->ioh.reader, avail);
            }

            avail = TSIOBufferReaderAvail(info->reserved.reader);
            if (avail + info->already >= info->need) {
                n = info->need - info->already;

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

            break;

        case TS_EVENT_VCONN_READ_COMPLETE:
        case TS_EVENT_VCONN_EOS:
            avail = TSIOBufferReaderAvail(info->ioh.reader);
            if (avail > 0) {
                TSIOBufferCopy(info->reserved.buffer, info->ioh.reader, avail, 0);
                TSIOBufferReaderConsume(info->ioh.reader, avail);
            }

            n = TSIOBufferReaderAvail(info->reserved.reader);

            info->eof = 1;
            break;

        default:                                // error
            info->err = 1;
            break;
    }

    if (info->wait && (n > 0 || info->eof || info->err)) {      // resume
        L = ci->routine.lua;
        mtx = ci->routine.mctx->mutexp;

        TSMutexLock(mtx);

        if (n > 0) {
            dst = TSmalloc(n);
            IOBufferReaderCopy(info->reserved.reader, dst, n);
            lua_pushlstring(L, (char*)dst, n);
            TSfree(dst);

            info->already += n;
            TSIOBufferReaderConsume(info->reserved.reader, n);

        } else {
            lua_pushnil(L);
        }

        info->wait = 0;

        TSContCall(ci->contp, TS_LUA_EVENT_COROUTINE_CONT, (void*)1);
        TSMutexUnlock(mtx);
    }

    return 0;
}
Ejemplo n.º 30
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);
}