static void
parse_response(StateInfo *state)
{
  TSIOBufferBlock block;
  TSParseResult pr = TS_PARSE_CONT;
  int64_t avail;
  char *start;

  block = TSIOBufferReaderStart(state->resp_io_buf_reader);

  while ((pr == TS_PARSE_CONT) && (block != NULL)) {
    start = (char *)TSIOBufferBlockReadStart(block, state->resp_io_buf_reader, &avail);
    if (avail > 0) {
      pr = TSHttpHdrParseResp(state->resp_info->parser, state->resp_info->buf, state->resp_info->http_hdr_loc,
                              (const char **)&start, (const char *)(start + avail));
    }
    block = TSIOBufferBlockNext(block);
  }

  if (pr != TS_PARSE_CONT) {
    state->resp_info->status = TSHttpHdrStatusGet(state->resp_info->buf, state->resp_info->http_hdr_loc);
    state->resp_info->parsed = true;
    TSDebug(PLUGIN_NAME, "HTTP Status: %d", state->resp_info->status);
  }
}
static char *
request_body_get(TSHttpTxn txnp, int *len)
{
  char *ret                           = NULL;
  TSIOBufferReader post_buffer_reader = TSHttpTxnPostBufferReaderGet(txnp);
  int64_t read_avail                  = TSIOBufferReaderAvail(post_buffer_reader);
  if (read_avail == 0) {
    TSIOBufferReaderFree(post_buffer_reader);
    return NULL;
  }

  ret = (char *)TSmalloc(sizeof(char) * read_avail);

  int64_t consumed      = 0;
  int64_t data_len      = 0;
  const char *char_data = NULL;
  TSIOBufferBlock block = TSIOBufferReaderStart(post_buffer_reader);
  while (block != NULL) {
    char_data = TSIOBufferBlockReadStart(block, post_buffer_reader, &data_len);
    memcpy(ret + consumed, char_data, data_len);
    consumed += data_len;
    block = TSIOBufferBlockNext(block);
  }
  TSIOBufferReaderFree(post_buffer_reader);

  *len = (int)consumed;
  return ret;
}
Exemplo n.º 3
0
int64_t
IOBufferReaderCopy(TSIOBufferReader readerp, void *buf, int64_t length)
{
    int64_t             avail, need, n;
    const char          *start;
    TSIOBufferBlock     blk;

    n = 0;
    blk = TSIOBufferReaderStart(readerp);

    while (blk) {
        start = TSIOBufferBlockReadStart(blk, readerp, &avail);
        need = length < avail ? length : avail;

        if (need > 0) {
            memcpy((char*)buf + n, start, need);
            length -= need;
            n += need;
        }

        if (length == 0)
            break;

        blk = TSIOBufferBlockNext(blk);
    }

    return n;
}
Exemplo n.º 4
0
/*-------------------------------------------------------------------------
  strsearch_ioreader
  Looks for string pattern in an iobuffer

  Input:
    reader   reader on a iobuffer
    pattern  string to look for (nul terminated)
  Output:
    nparse   number of chars scanned, excluding the matching pattern
  Return Value:
    STR_SUCCESS if pattern found
    STR_PARTIAL if pattern found partially
    STR_FAIL    if pattern not found
  -------------------------------------------------------------------------*/
static StrOperationResult
strsearch_ioreader(TSIOBufferReader reader, const char *pattern, int *nparse)
{
  int index = 0;
  TSIOBufferBlock block = TSIOBufferReaderStart(reader);
  int slen = strlen(pattern);

  if (slen <= 0) {
    return STR_FAIL;
  }

  *nparse = 0;

  /* Loop thru each block while we've not yet found the pattern */
  while ((block != NULL) && (index < slen)) {
    int64_t blocklen;
    const char *blockptr = TSIOBufferBlockReadStart(block, reader, &blocklen);
    const char *ptr;

    for (ptr = blockptr; ptr < blockptr + blocklen; ptr++) {
      (*nparse)++;
      if (*ptr == pattern[index]) {
        index++;
        if (index == slen) {
          break;
        }
      } else {
        index = 0;
      }
    }

    /* Parse next block */
    block = TSIOBufferBlockNext(block);
  }

  *nparse -= index;             /* Adjust nparse so it doesn't include matching chars */
  if (index == slen) {
    TSDebug(DBG_TAG, "strfind: match for %s at position %d", pattern, *nparse);
    return STR_SUCCESS;
  } else if (index > 0) {
    TSDebug(DBG_TAG, "strfind: partial match for %s at position %d", pattern, *nparse);
    return STR_PARTIAL;
  } else {
    TSDebug(DBG_TAG, "strfind no match for %s", pattern);
    return STR_FAIL;
  }
}
Exemplo n.º 5
0
int
ts_http_fetcher_parse_header(http_fetcher *fch)
{
    int64_t         avail, used;
    const char      *start, *guard, *end;
    int             ret;
    TSIOBufferBlock blk;

    blk = TSIOBufferReaderStart(fch->resp_reader);

    while (blk) {
        guard = start = TSIOBufferBlockReadStart(blk, fch->resp_reader, &avail);
        end = start + avail;

        ret = TSHttpHdrParseResp(fch->http_parser, fch->hdr_bufp, fch->hdr_loc, &start, end);

        switch (ret) {

            case TS_PARSE_ERROR:
                return -1;

            case TS_PARSE_DONE:
                used = start - guard;
                TSIOBufferCopy(fch->hdr_buffer, fch->resp_reader, used, 0);
                TSIOBufferReaderConsume(fch->resp_reader, used);

                ts_http_fetcher_extract(fch);
                // ts_http_fetcher_setup_filter(fch);

                fch->header_done = 1;

                return 0;

            default:
                TSIOBufferCopy(fch->hdr_buffer, fch->resp_reader, avail, 0);
                TSIOBufferReaderConsume(fch->resp_reader, avail);
                break;
        }

        blk = TSIOBufferBlockNext(blk);
    }

    return 0;
}
Exemplo n.º 6
0
int
ts_dechunk_process(ts_dechunk_info *info, TSIOBufferReader readerp, TSIOBuffer bufp, int end)
{
    int         n;
    int64_t     avail, need;
    int64_t     blk_len;
    const char  *start;
    const char  *cur;
    TSIOBufferBlock blk, next_blk;

    blk = TSIOBufferReaderStart(readerp);

    while (blk) {

        next_blk = TSIOBufferBlockNext(blk);

        start = TSIOBufferBlockReadStart(blk, readerp, &blk_len);
        avail = blk_len;

        if (avail) {

            do {
                cur = start + blk_len - avail;

                switch (info->state) {

                    case TS_DECHUNK_WAIT_LENGTH:
                        n = ts_dechunk_extract_frag_len(info, cur, avail);
                        if (n < 0)
                            return -1;

                        avail -= n;

                        if (!info->dechunk_enabled)
                            TSIOBufferCopy(bufp, readerp, n, 0);

                        TSIOBufferReaderConsume(readerp, n);
                        break;

                    case TS_DECHUNK_WAIT_RETURN:
                        n = ts_dechunk_extract_return(info, cur, avail, 0);
                        avail -= n;

                        if (!info->dechunk_enabled)
                            TSIOBufferCopy(bufp, readerp, n, 0);

                        TSIOBufferReaderConsume(readerp, n);
                        break;

                    case TS_DECHUNK_WAIT_DATA:
                        if (info->frag_len + avail <= info->frag_total) {
                            TSIOBufferCopy(bufp, readerp, avail, 0);
                            TSIOBufferReaderConsume(readerp, avail);
                            info->frag_len += avail;
                            avail = 0;
                            break;
                        } else {
                            need = info->frag_total - info->frag_len;
                            if (need) {
                                TSIOBufferCopy(bufp, readerp, need, 0);
                                TSIOBufferReaderConsume(readerp, need);
                                info->frag_len += need;
                                avail -= need;
                            }

                            info->cr = 0;
                            info->state = TS_DECHUNK_WAIT_RETURN_END;
                        }

                        break;

                    case TS_DECHUNK_WAIT_RETURN_END:
                        n = ts_dechunk_extract_return(info, cur, avail, 1);
                        avail -= n;

                        if (!info->dechunk_enabled)
                            TSIOBufferCopy(bufp, readerp, n, 0);

                        TSIOBufferReaderConsume(readerp, n);
                        break;

                    case TS_DECHUNK_DATA_DONE:

                        if (!info->dechunk_enabled)
                            TSIOBufferCopy(bufp, readerp, avail, 0);

                        TSIOBufferReaderConsume(readerp, avail);
                        avail = 0;
                        info->done = 1;
                        break;

                    default:
                        break;
                }
            } while (avail > 0);
        }

        if (info->done)
            break;

        blk = next_blk;
    }

    if (info->done) {
        return 1;

    } else if (end) {
        return -1;

    } else {
        return 0;
    }
}
Exemplo n.º 7
0
static int
ts_http_fetcher_verify_chunked(http_fetcher *fch, int code)
{
    int         n;
    int64_t     avail, need;
    int64_t     blk_len;
    const char  *start;
    const char  *cur;
    TSIOBufferBlock blk, next_blk;

    chunked_info *ci = &fch->cinfo;
    blk = TSIOBufferReaderStart(fch->flow_reader);

    while (blk) {

        next_blk = TSIOBufferBlockNext(blk);

        start = TSIOBufferBlockReadStart(blk, fch->flow_reader, &blk_len);
        avail = blk_len;

        if (avail) {

            do {
                cur = start + blk_len - avail;

                switch (ci->state) {

                    case CHUNK_WAIT_LENGTH:
                        n = chunked_extract_frag_len(ci, cur, avail);
                        if (n < 0)
                            return BODY_ERROR;

                        avail -= n;

                        if (!ci->dechunk_enabled)
                            TSIOBufferCopy(fch->body_buffer, fch->flow_reader, n, 0);

                        TSIOBufferReaderConsume(fch->flow_reader, n);
                        break;

                    case CHUNK_WAIT_RETURN:
                        n = chunked_extract_return(ci, cur, avail, 0);
                        avail -= n;

                        if (!ci->dechunk_enabled)
                            TSIOBufferCopy(fch->body_buffer, fch->flow_reader, n, 0);

                        TSIOBufferReaderConsume(fch->flow_reader, n);
                        break;

                    case CHUNK_WAIT_DATA:
                        if (ci->frag_len + avail <= ci->frag_total) {
                            TSIOBufferCopy(fch->body_buffer, fch->flow_reader, avail, 0);
                            TSIOBufferReaderConsume(fch->flow_reader, avail);
                            ci->frag_len += avail;
                            avail = 0;
                            break;
                        } else {
                            need = ci->frag_total - ci->frag_len;
                            if (need) {
                                TSIOBufferCopy(fch->body_buffer, fch->flow_reader, need, 0);
                                TSIOBufferReaderConsume(fch->flow_reader, need);
                                ci->frag_len += need;
                                avail -= need;
                            }

                            ci->cr = 0;
                            ci->state = CHUNK_WAIT_RETURN_END;
                        }

                        break;

                    case CHUNK_WAIT_RETURN_END:
                        n = chunked_extract_return(ci, cur, avail, 1);
                        avail -= n;

                        if (!ci->dechunk_enabled)
                            TSIOBufferCopy(fch->body_buffer, fch->flow_reader, n, 0);

                        TSIOBufferReaderConsume(fch->flow_reader, n);
                        break;

                    case CHUNK_DATA_DONE:

                        if (!ci->dechunk_enabled)
                            TSIOBufferCopy(fch->body_buffer, fch->flow_reader, avail, 0);

                        TSIOBufferReaderConsume(fch->flow_reader, avail);
                        avail = 0;
                        ci->done = 1;
                        break;

                    default:
                        break;
                }
            } while (avail > 0);
        }

        if (ci->done)
            break;

        blk = next_blk;
    }

    if (ci->done) {
        return BODY_COMPLETE;

    } else if (code == BODY_COMPLETE) {
        return BODY_ERROR;

    } else {
        return BODY_READY;
    }
}
Exemplo n.º 8
0
/*-------------------------------------------------------------------------
  strextract_ioreader
  Extract a string from an iobuffer.
  Start reading at position offset in iobuffer and extract until the
  string end_pattern is found.

  Input:
    reader      reader on a iobuffer
    offset      position to start reading
    end_pattern the termination string (nul terminated)
  Output:
    buffer      if success, contains the extracted string, nul terminated
    buflen      if success, contains the buffer length (excluding null char).
  Return Value:
    STR_SUCCESS if extraction successful
    STR_PARTIAL if extraction not yet completed
    STR_FAIL    if extraction failed
  -------------------------------------------------------------------------*/
static int
strextract_ioreader(TSIOBufferReader reader, int offset, const char *end_pattern, char *buffer, int *buflen)
{
  int buf_idx = 0;
  int p_idx = 0;
  int nbytes_so_far = 0;
  int plen = strlen(end_pattern);
  const char *ptr;
  TSIOBufferBlock block = TSIOBufferReaderStart(reader);

  if (plen <= 0) {
    return STR_FAIL;
  }

  /* Now start extraction */
  while ((block != NULL) && (p_idx < plen) && (buf_idx < PSI_FILENAME_MAX_SIZE)) {
    int64_t blocklen;
    const char *blockptr = TSIOBufferBlockReadStart(block, reader, &blocklen);

    for (ptr = blockptr; ptr < blockptr + blocklen; ptr++, nbytes_so_far++) {
      if (nbytes_so_far >= offset) {

        /* Add a new character to the filename */
        buffer[buf_idx++] = *ptr;

        /* If we have reach the end of the filename, we're done */
        if (end_pattern[p_idx] == *ptr) {
          p_idx++;
          if (p_idx == plen) {
            break;
          }
        } else {
          p_idx = 0;
        }

        /* The filename is too long, something is fishy... let's abort extraction */
        if (buf_idx >= PSI_FILENAME_MAX_SIZE) {
          break;
        }
      }
    }

    block = TSIOBufferBlockNext(block);
  }

  /* Error, could not read end of filename */
  if (buf_idx >= PSI_FILENAME_MAX_SIZE) {
    TSDebug(DBG_TAG, "strextract: filename too long");
    *buflen = 0;
    return STR_FAIL;
  }

  /* Full Match */
  if (p_idx == plen) {
    /* Nul terminate the filename, remove the end_pattern copied into the buffer */
    *buflen = buf_idx - plen;
    buffer[*buflen] = '\0';
    TSDebug(DBG_TAG, "strextract: filename = |%s|", buffer);
    return STR_SUCCESS;
  }
  /* End of filename not yet reached we need to read some more data */
  else {
    TSDebug(DBG_TAG, "strextract: partially extracted filename");
    *buflen = buf_idx - p_idx;
    return STR_PARTIAL;
  }
}
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;
}
Exemplo n.º 10
0
/**
 * Process data from ATS.
 *
 * Process data from one of the ATS events.
 *
 * @param[in,out] contp - the continuation
 * @param[in,out] ibd - the filter descriptor
 */
static void process_data(TSCont contp, ibd_ctx *ibd)
{
    int64_t ntodo;
    int64_t navail;
    TSIOBufferReader input_reader, output_reader;
    TSIOBufferBlock block;
    const char *buf;
    int64_t nbytes;
    ib_status_t rc;

    ib_filter_ctx *fctx = ibd->data;

    ib_txn_ctx *data = TSContDataGet(contp);
    TSVIO  input_vio = TSVConnWriteVIOGet(contp);
    TSIOBuffer in_buf = TSVIOBufferGet(input_vio);

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

    /* Test for EOS */
    if (in_buf == NULL) {
        /* flush anything we have buffered.  This is final! */
        flush_data(fctx, -1, 1);
        return;
    }

    ntodo = TSVIONTodoGet(input_vio);

    /* Test for first time, and initialise.  */
    if (!fctx->output_buffer) {
        fctx->output_buffer = TSIOBufferCreate();
        ib_mm_register_cleanup(data->tx->mm,
                               (ib_mm_cleanup_fn_t) TSIOBufferDestroy,
                               (void*) fctx->output_buffer);
        output_reader = TSIOBufferReaderAlloc(fctx->output_buffer);
        fctx->output_vio = TSVConnWrite(TSTransformOutputVConnGet(contp), contp, output_reader, TSVIONBytesGet(input_vio));

        fctx->buffer = TSIOBufferCreate();
        ib_mm_register_cleanup(data->tx->mm,
                               (ib_mm_cleanup_fn_t) TSIOBufferDestroy,
                               (void*) fctx->buffer);
        fctx->reader = TSIOBufferReaderAlloc(fctx->buffer);

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

/* Do we still have to delay feeding the first data to Ironbee
 * to keep the IB events in their proper order?
 *
 * Appears maybe not, so let's do nothing until it shows signs of breakage.
 */
#if BUFFER_FIRST
        /* First time through we can only buffer data until headers are sent. */
        fctx->first_time = 1;
        input_reader = TSVIOReaderGet(input_vio);
        fctx->buffered = TSIOBufferCopy(fctx->buffer, TSVIOReaderGet(input_vio),
                                        ntodo, 0);
        TSIOBufferReaderConsume(input_reader, fctx->buffered);

        /* Do we need to request more input or just continue? */
        TSVIONDoneSet(input_vio, fctx->buffu`ered + fctx->bytes_done);

        TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_READY, input_vio);
        return;
#endif
    }

    /* second time through we have to feed already-buffered data through
     * ironbee while retaining it in buffer.  Regardless of what else happens.
     */
#if BUFFER_FIRST
    if (fctx->first_time) {
        fctx->first_time = 0;
        for (block = TSIOBufferStart(fctx->buffer);
	     block != NULL;
             block = TSIOBufferBlockNext(block)) {

            //nbytes = TSIOBufferBlockDataSizeGet(block);
            /* FIXME - do this without a reader ? */
            buf = TSIOBufferBlockReadStart(block, fctx->reader, &nbytes);
            //rc = examine_data_chunk(ibd->ibd, data->tx, buf, nbytes);
            rc = (*ibd->ibd->ib_notify_body)(data->tx->ib, data->tx, buf, nbytes);
            if (rc != IB_OK) {
                // FIXME ???
            }
        }
    }
#endif

    /* Test for EOS */
    if (ntodo == 0) {
        TSDebug("[ironbee]", "ntodo zero before consuming data");
        /* Call back the input VIO continuation to let it know that we
         * have completed the write operation.
         */
        TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_COMPLETE, input_vio);
        return;
    }

    /* OK, there's some input awaiting our attention */
    input_reader = TSVIOReaderGet(input_vio);
    while (navail = TSIOBufferReaderAvail(input_reader), navail > 0) {
        block = TSIOBufferReaderStart(input_reader);
        buf = TSIOBufferBlockReadStart(block, input_reader, &nbytes);
        rc = (*ibd->ibd->ib_notify_body)(data->tx->ib, data->tx, buf, nbytes);
        if (rc != IB_OK) {
            // FIXME ???
        }
        rc = buffer_data_chunk(fctx, input_reader, nbytes);
        if (rc != IB_OK) {
            // FIXME ???
        }
        TSIOBufferReaderConsume(input_reader, nbytes);
        TSVIONDoneSet(input_vio, TSVIONDoneGet(input_vio) + nbytes);
    }

    ntodo = TSVIONTodoGet(input_vio);
    if (ntodo == 0) {
        TSDebug("[ironbee]", "ntodo zero after consuming data");
        /* Call back the input VIO continuation to let it know that we
         * have completed the write operation.
         */
        TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_COMPLETE, input_vio);
    }
    else {
        /* Call back the input VIO continuation to let it know that we
         * are ready for more data.
         */
        TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_READY, input_vio);
    }
}