We've been chasing a strange problem with an ironbee
test case.  As the HTTP header size (from the method
to the blank line) grows above 4K, TSAPI 'loses' the
first 4Kb.  Request line details (method, url, version)
are fine if we use their explicit APIs, but the data
are lost/

I'll attach a mini demo-plugin that reproduces the problem.
The essence of it can be boiled down to:

    TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc);

    iobufp = TSIOBufferCreate();
    TSHttpHdrPrint(bufp, hdr_loc, iobufp);

    readerp = TSIOBufferReaderAlloc(iobufp);
    blockp = TSIOBufferReaderStart(readerp);

    len = TSIOBufferBlockReadAvail(blockp, readerp);

    head_buf = TSIOBufferBlockReadStart(blockp, readerp, &len);


What happens here is that the first 4K of a request are
'lost' in TSHttpHdrPrint.  Thus all we see in head_buf
is the last few bytes of a header a little larger than 4K.
I think the culprit is the do { } loop at lines 3603-3617
of InkAPI.cc, which goes around twice and overwrites the
first 4K on the second time round.

In addition to the demo plugin, I'll attach the two
testcases my colleague sent me.  It demonstrates that
a single extra byte in the header makes the difference
between working fine and provoking the problem.

A bug or a PBKAC?

[Bcc: my colleague]

-- 
Nick Kew
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <ts/ts.h>


static void process_hdr(TSHttpTxn txnp)
{
    TSMBuffer bufp;
    TSIOBuffer iobufp;
    TSIOBufferReader readerp;
    TSIOBufferBlock blockp;
    TSMLoc hdr_loc;
    char *head_buf;
    int64_t len;

    TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc);

    iobufp = TSIOBufferCreate();
    TSHttpHdrPrint(bufp, hdr_loc, iobufp);

    readerp = TSIOBufferReaderAlloc(iobufp);
    blockp = TSIOBufferReaderStart(readerp);

    len = TSIOBufferBlockReadAvail(blockp, readerp);

    for (head_buf = (void *)TSIOBufferBlockReadStart(blockp, readerp, &len);
         len > 0;
         head_buf = (void *)TSIOBufferBlockReadStart(
                        TSIOBufferReaderStart(readerp), readerp, &len)) {

        TSError("Got %d bytes starting %.12s\n", (int)len, head_buf);

        /* if there's more to come, go round again ... */
        TSIOBufferReaderConsume(readerp, len);
    }

    TSIOBufferReaderFree(readerp);
    TSIOBufferDestroy(iobufp);
    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
}

static int test_plugin(TSCont contp, TSEvent event, void *edata)
{
    TSCont mycont;
    TSHttpTxn txnp = (TSHttpTxn) edata;

    switch (event) {

        case TS_EVENT_HTTP_TXN_START:
            mycont = TSContCreate(test_plugin, TSMutexCreate());
            TSHttpTxnHookAdd(txnp, TS_HTTP_PRE_REMAP_HOOK, contp);
            break;

        case TS_EVENT_HTTP_PRE_REMAP:
            process_hdr(txnp);
            break;

        default:
            TSError("BUG: unhandled event %d in ironbee_plugin\n", event);
            break;
    }
    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);

    return 0;
}

void TSPluginInit(int argc, const char *argv[])
{
    TSCont cont = TSContCreate(test_plugin, TSMutexCreate());
    TSHttpHookAdd(TS_HTTP_TXN_START_HOOK, cont);
    return;
}

Reply via email to