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; }