This is an automated email from the ASF dual-hosted git repository. bcall pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push: new 473e054 Fix problems with "Probe" option for X-Debug MIME header field. (#6197) 473e054 is described below commit 473e0549cbb7bda763340b842d447d9db0d49879 Author: Walt Karas <wka...@verizonmedia.com> AuthorDate: Fri Jan 17 14:16:57 2020 -0600 Fix problems with "Probe" option for X-Debug MIME header field. (#6197) Fix problems with "Probe" option for X-Debug MIME header field. - Adds exercise of "Probe" to the existing x_remap Au test. - Remove memory leaks and risk of double deletion in xdebug plugin. --- plugins/xdebug/Cleanup.h | 186 ++++++++++++ plugins/xdebug/Makefile.inc | 4 +- plugins/xdebug/xdebug.cc | 69 +++-- plugins/xdebug/xdebug_transforms.cc | 44 +-- tests/gold_tests/pluginTest/xdebug/x_remap/four.in | 3 +- tests/gold_tests/pluginTest/xdebug/x_remap/fwd1.in | 3 +- tests/gold_tests/pluginTest/xdebug/x_remap/fwd2.in | 3 +- tests/gold_tests/pluginTest/xdebug/x_remap/fwd3.in | 3 +- tests/gold_tests/pluginTest/xdebug/x_remap/fwd4.in | 3 +- tests/gold_tests/pluginTest/xdebug/x_remap/fwd5.in | 3 +- tests/gold_tests/pluginTest/xdebug/x_remap/none.in | 3 +- tests/gold_tests/pluginTest/xdebug/x_remap/one.in | 3 +- .../gold_tests/pluginTest/xdebug/x_remap/out.gold | 315 ++++++++++++++++++++- .../gold_tests/pluginTest/xdebug/x_remap/three.in | 3 +- tests/gold_tests/pluginTest/xdebug/x_remap/two.in | 3 +- .../pluginTest/xdebug/x_remap/x_remap.gold | 6 +- .../pluginTest/xdebug/x_remap/x_remap.test.py | 4 +- 17 files changed, 577 insertions(+), 81 deletions(-) diff --git a/plugins/xdebug/Cleanup.h b/plugins/xdebug/Cleanup.h new file mode 100644 index 0000000..453903c --- /dev/null +++ b/plugins/xdebug/Cleanup.h @@ -0,0 +1,186 @@ +/** + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/** + * @file Cleanup.h + * @brief Easy-to-use utilities to avoid resource leaks or double-releases of resources. Independent of the rest + * of the CPPAPI. + */ + +#pragma once + +#include <type_traits> +#include <memory> + +#include <ts/ts.h> + +namespace atscppapi +{ +// For TS API types TSXxx with a TSXxxDestroy function, define standard deleter TSXxxDeleter, and use it to +// define TSXxxUniqPtr (specialization of std::unique_ptr). X() is used when the destroy function returns void, +// Y() is used when the destroy function returns TSReturnCode. + +#if defined(X) +#error "X defined as preprocessor symbol" +#endif + +#define X(NAME_SEGMENT) \ + struct TS##NAME_SEGMENT##Deleter { \ + void \ + operator()(TS##NAME_SEGMENT ptr) \ + { \ + TS##NAME_SEGMENT##Destroy(ptr); \ + } \ + }; \ + using TS##NAME_SEGMENT##UniqPtr = std::unique_ptr<std::remove_pointer_t<TS##NAME_SEGMENT>, TS##NAME_SEGMENT##Deleter>; + +#if defined(Y) +#error "Y defined as preprocessor symbol" +#endif + +#define Y(NAME_SEGMENT) \ + struct TS##NAME_SEGMENT##Deleter { \ + void \ + operator()(TS##NAME_SEGMENT ptr) \ + { \ + TSAssert(TS##NAME_SEGMENT##Destroy(ptr) == TS_SUCCESS); \ + } \ + }; \ + using TS##NAME_SEGMENT##UniqPtr = std::unique_ptr<std::remove_pointer_t<TS##NAME_SEGMENT>, TS##NAME_SEGMENT##Deleter>; + +Y(MBuffer) // Defines TSMBufferDeleter and TSMBufferUniqPtr. +X(MimeParser) // Defines TSMimeParserDeleter and TSMimeParserUniqPtr. +X(Thread) // Defines TSThreadDeleter and TSThreadUniqPtr. +X(Mutex) // Defines TSMutexDeleter and TSMutexUniqPtr. +Y(CacheKey) // Defines TSCacheKeyDeleter and TSCacheKeyUniqPtr. +X(Cont) // Defines TSContDeleter and TSContUniqPtr. +X(SslContext) // Defines TSSslContextDeleter and TSSslContextUniqPtr. +X(IOBuffer) // Defines TSIOBufferDeleter and TSIOBufferUniqPtr. +Y(TextLogObject) // Defines TSTextLogObjectDeleter and TSTextLogObjectUniqPtr. +X(Uuid) // Defines TSUuidDeleter and TSUuidUniqPtr. + +#undef X +#undef Y + +// Deleter and unique pointer for memory buffer returned by TSalloc(), TSrealloc(), Tstrdup(), TSsrtndup(). +// +struct TSMemDeleter { + void + operator()(void *ptr) + { + TSfree(ptr); + } +}; +using TSMemUniqPtr = std::unique_ptr<void, TSMemDeleter>; + +// Deleter and unique pointer for TSIOBufferReader. Care must be taken that the reader is deleted before the +// TSIOBuffer to which it refers is deleted. +// +struct TSIOBufferReaderDeleter { + void + operator()(TSIOBufferReader ptr) + { + TSIOBufferReaderFree(ptr); + } +}; +using TSIOBufferReaderUniqPtr = std::unique_ptr<std::remove_pointer_t<TSIOBufferReader>, TSIOBufferReaderDeleter>; + +class TxnAuxDataMgrBase +{ +protected: + struct MgrData_ { + TSCont txnCloseContp = nullptr; + int txnArgIndex = -1; + }; + +public: + class MgrData : private MgrData_ + { + friend class TxnAuxDataMgrBase; + }; + +protected: + static MgrData_ & + access(MgrData &md) + { + return md; + } +}; + +using TxnAuxMgrData = TxnAuxDataMgrBase::MgrData; + +// Class to manage auxilliary data for a transaction. If an instance is created for the transaction, the instance +// will be deleted on the TXN_CLOSE transaction hook (which is always triggered for all transactions). +// The TxnAuxData class must have a public default constructor. +// +template <class TxnAuxData, TxnAuxMgrData &MDRef> class TxnAuxDataMgr : private TxnAuxDataMgrBase +{ +public: + using Data = TxnAuxData; + + // This must be called from the plugin init function. arg_name is the name for the transaction argument used + // to store the pointer to the auxiliary data class instance. Repeated calls are ignored. + // + static void + init(char const *arg_name, char const *arg_desc = "per-transaction auxiliary data") + { + MgrData_ &md = access(MDRef); + + if (md.txnArgIndex >= 0) { + return; + } + + TSReleaseAssert(TSHttpTxnArgIndexReserve(arg_name, arg_desc, &md.txnArgIndex) == TS_SUCCESS); + TSReleaseAssert(md.txnCloseContp = TSContCreate(_deleteAuxData, nullptr)); + } + + // Get a reference to the auxiliary data for a transaction. + // + static TxnAuxData & + data(TSHttpTxn txn) + { + MgrData_ &md = access(MDRef); + + TSAssert(md.txnArgIndex >= 0); + + auto d = static_cast<TxnAuxData *>(TSHttpTxnArgGet(txn, md.txnArgIndex)); + if (!d) { + d = new TxnAuxData; + + TSHttpTxnArgSet(txn, md.txnArgIndex, d); + + TSHttpTxnHookAdd(txn, TS_HTTP_TXN_CLOSE_HOOK, md.txnCloseContp); + } + return *d; + } + +private: + static int + _deleteAuxData(TSCont, TSEvent, void *edata) + { + MgrData_ &md = access(MDRef); + + auto txn = static_cast<TSHttpTxn>(edata); + auto data = static_cast<TxnAuxData *>(TSHttpTxnArgGet(txn, md.txnArgIndex)); + delete data; + TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE); + return 0; + }; +}; + +} // end namespace atscppapi diff --git a/plugins/xdebug/Makefile.inc b/plugins/xdebug/Makefile.inc index 1e41324..a69e223 100644 --- a/plugins/xdebug/Makefile.inc +++ b/plugins/xdebug/Makefile.inc @@ -15,4 +15,6 @@ # limitations under the License. pkglib_LTLIBRARIES += xdebug/xdebug.la -xdebug_xdebug_la_SOURCES = xdebug/xdebug.cc +xdebug_xdebug_la_SOURCES = \ +xdebug/Cleanup.h \ +xdebug/xdebug.cc diff --git a/plugins/xdebug/xdebug.cc b/plugins/xdebug/xdebug.cc index a3a2443..3493575 100644 --- a/plugins/xdebug/xdebug.cc +++ b/plugins/xdebug/xdebug.cc @@ -22,6 +22,8 @@ #include <strings.h> #include <sstream> #include <cstring> +#include <atomic> +#include <memory> #include <getopt.h> #include <cstdint> #include <cinttypes> @@ -32,6 +34,34 @@ #include "tscore/ink_defs.h" #include "tscpp/util/PostScript.h" #include "tscpp/util/TextView.h" +#include "Cleanup.h" + +namespace +{ +struct BodyBuilder { + atscppapi::TSContUniqPtr transform_connp; + atscppapi::TSIOBufferUniqPtr output_buffer; + // It's important that output_reader comes after output_buffer so it will be deleted first. + atscppapi::TSIOBufferReaderUniqPtr output_reader; + TSVIO output_vio = nullptr; + bool wrote_prebody = false; + bool wrote_body = false; + bool hdr_ready = false; + std::atomic_flag wrote_postbody; + + int64_t nbytes = 0; +}; + +struct XDebugTxnAuxData { + std::unique_ptr<BodyBuilder> body_builder; + unsigned xheaders = 0; +}; + +atscppapi::TxnAuxMgrData mgrData; + +using AuxDataMgr = atscppapi::TxnAuxDataMgr<XDebugTxnAuxData, mgrData>; + +} // end anonymous namespace #include "xdebug_headers.cc" #include "xdebug_transforms.cc" @@ -53,8 +83,6 @@ enum { XHEADER_X_PSELECT_KEY = 1u << 10, }; -static int XArgIndex = 0; -static int BodyBuilderArgIndex = 0; static TSCont XInjectHeadersCont = nullptr; static TSCont XDeleteDebugHdrCont = nullptr; @@ -382,7 +410,7 @@ XInjectResponseHeaders(TSCont /* contp */, TSEvent event, void *edata) TSReleaseAssert(event == TS_EVENT_HTTP_SEND_RESPONSE_HDR); - uintptr_t xheaders = reinterpret_cast<uintptr_t>(TSHttpTxnArgGet(txn, XArgIndex)); + unsigned xheaders = AuxDataMgr::data(txn).xheaders; if (xheaders == 0) { goto done; } @@ -422,14 +450,14 @@ XInjectResponseHeaders(TSCont /* contp */, TSEvent event, void *edata) } if (xheaders & XHEADER_X_PROBE_HEADERS) { - BodyBuilder *data = static_cast<BodyBuilder *>(TSHttpTxnArgGet(txn, BodyBuilderArgIndex)); + BodyBuilder *data = AuxDataMgr::data(txn).body_builder.get(); TSDebug("xdebug_transform", "XInjectResponseHeaders(): client resp header ready"); if (data == nullptr) { TSHttpTxnReenable(txn, TS_EVENT_HTTP_ERROR); return TS_ERROR; } data->hdr_ready = true; - writePostBody(data); + writePostBody(txn, data); } if (xheaders & XHEADER_X_PSELECT_KEY) { @@ -493,9 +521,9 @@ isFwdFieldValue(std::string_view value, intmax_t &fwdCnt) static int XScanRequestHeaders(TSCont /* contp */, TSEvent event, void *edata) { - TSHttpTxn txn = static_cast<TSHttpTxn>(edata); - uintptr_t xheaders = 0; - intmax_t fwdCnt = 0; + TSHttpTxn txn = static_cast<TSHttpTxn>(edata); + unsigned xheaders = 0; + intmax_t fwdCnt = 0; TSMLoc field, next; TSMBuffer buffer; TSMLoc hdr; @@ -550,26 +578,17 @@ XScanRequestHeaders(TSCont /* contp */, TSEvent event, void *edata) } else if (header_field_eq("probe", value, vsize)) { xheaders |= XHEADER_X_PROBE_HEADERS; + auto &auxData = AuxDataMgr::data(txn); + // prefix request headers and postfix response headers BodyBuilder *data = new BodyBuilder(); - data->txn = txn; + auxData.body_builder.reset(data); TSVConn connp = TSTransformCreate(body_transform, txn); - TSContDataSet(connp, data); + data->transform_connp.reset(connp); + TSContDataSet(connp, txn); TSHttpTxnHookAdd(txn, TS_HTTP_RESPONSE_TRANSFORM_HOOK, connp); - // store data pointer in txnarg to use in global cont XInjectResponseHeaders - TSHttpTxnArgSet(txn, BodyBuilderArgIndex, data); - - // create a self-cleanup on close - auto cleanupBodyBuilder = [](TSCont /* contp */, TSEvent event, void *edata) -> int { - TSHttpTxn txn = static_cast<TSHttpTxn>(edata); - BodyBuilder *data = static_cast<BodyBuilder *>(TSHttpTxnArgGet(txn, BodyBuilderArgIndex)); - delete data; - return TS_EVENT_NONE; - }; - TSHttpTxnHookAdd(txn, TS_HTTP_TXN_CLOSE_HOOK, TSContCreate(cleanupBodyBuilder, nullptr)); - // disable writing to cache because we are injecting data into the body. TSHttpTxnReqCacheableSet(txn, 0); TSHttpTxnRespCacheableSet(txn, 0); @@ -608,7 +627,7 @@ XScanRequestHeaders(TSCont /* contp */, TSEvent event, void *edata) TSDebug("xdebug", "adding response hook for header mask %p and forward count %" PRIiMAX, reinterpret_cast<void *>(xheaders), fwdCnt); TSHttpTxnHookAdd(txn, TS_HTTP_SEND_RESPONSE_HDR_HOOK, XInjectHeadersCont); - TSHttpTxnArgSet(txn, XArgIndex, reinterpret_cast<void *>(xheaders)); + AuxDataMgr::data(txn).xheaders = xheaders; if (fwdCnt == 0) { // X-Debug header has to be deleted, but not too soon for other plugins to see it. @@ -688,9 +707,9 @@ TSPluginInit(int argc, const char *argv[]) } xDebugHeader.len = strlen(xDebugHeader.str); + AuxDataMgr::init("xdebug"); + // Setup the global hook - TSReleaseAssert(TSHttpTxnArgIndexReserve("xdebug", "xdebug header requests", &XArgIndex) == TS_SUCCESS); - TSReleaseAssert(TSHttpTxnArgIndexReserve("bodyTransform", "BodyBuilder*", &XArgIndex) == TS_SUCCESS); TSReleaseAssert(XInjectHeadersCont = TSContCreate(XInjectResponseHeaders, nullptr)); TSReleaseAssert(XDeleteDebugHdrCont = TSContCreate(XDeleteDebugHdr, nullptr)); TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, TSContCreate(XScanRequestHeaders, nullptr)); diff --git a/plugins/xdebug/xdebug_transforms.cc b/plugins/xdebug/xdebug_transforms.cc index a5bc75a..e1019e7 100644 --- a/plugins/xdebug/xdebug_transforms.cc +++ b/plugins/xdebug/xdebug_transforms.cc @@ -21,25 +21,11 @@ #include <stdio.h> #include <string.h> #include <functional> -#include <atomic> #include "ts/ts.h" static const std::string_view MultipartBoundary{"\r\n--- ATS xDebug Probe Injection Boundary ---\r\n\r\n"}; -struct BodyBuilder { - TSVIO output_vio = nullptr; - TSIOBuffer output_buffer = nullptr; - TSIOBufferReader output_reader = nullptr; - bool wrote_prebody = false; - bool wrote_body = false; - bool hdr_ready = false; - std::atomic_flag wrote_postbody; - - int64_t nbytes = 0; - TSHttpTxn txn = nullptr; -}; - static char Hostname[1024]; static std::string @@ -65,12 +51,12 @@ getPostBody(TSHttpTxn txn) } static void -writePostBody(BodyBuilder *data) +writePostBody(TSHttpTxn txn, BodyBuilder *data) { if (data->wrote_body && data->hdr_ready && !data->wrote_postbody.test_and_set()) { TSDebug("xdebug_transform", "body_transform(): Writing postbody headers..."); - std::string postbody = getPostBody(data->txn); - TSIOBufferWrite(data->output_buffer, postbody.data(), postbody.length()); + std::string postbody = getPostBody(txn); + TSIOBufferWrite(data->output_buffer.get(), postbody.data(), postbody.length()); data->nbytes += postbody.length(); TSVIONBytesSet(data->output_vio, data->nbytes); TSVIOReenable(data->output_vio); @@ -80,15 +66,13 @@ writePostBody(BodyBuilder *data) static int body_transform(TSCont contp, TSEvent event, void *edata) { - BodyBuilder *data = static_cast<BodyBuilder *>(TSContDataGet(contp)); + TSHttpTxn txn = static_cast<TSHttpTxn>(TSContDataGet(contp)); + BodyBuilder *data = AuxDataMgr::data(txn).body_builder.get(); if (!data) { - TSContDestroy(contp); return TS_ERROR; } if (TSVConnClosedGet(contp)) { - // write connection destroyed. cleanup. - delete data; - TSContDestroy(contp); + // write connection destroyed. return 0; } @@ -108,16 +92,16 @@ body_transform(TSCont contp, TSEvent event, void *edata) TSDebug("xdebug_transform", "body_transform(): Event is TS_EVENT_VCONN_WRITE_READY"); // fall through default: - if (!data->output_buffer) { - data->output_buffer = TSIOBufferCreate(); - data->output_reader = TSIOBufferReaderAlloc(data->output_buffer); - data->output_vio = TSVConnWrite(TSTransformOutputVConnGet(contp), contp, data->output_reader, INT64_MAX); + if (!data->output_buffer.get()) { + data->output_buffer.reset(TSIOBufferCreate()); + data->output_reader.reset(TSIOBufferReaderAlloc(data->output_buffer.get())); + data->output_vio = TSVConnWrite(TSTransformOutputVConnGet(contp), contp, data->output_reader.get(), INT64_MAX); } if (data->wrote_prebody == false) { TSDebug("xdebug_transform", "body_transform(): Writing prebody headers..."); - std::string prebody = getPreBody(data->txn); - TSIOBufferWrite(data->output_buffer, prebody.data(), prebody.length()); // write prebody + std::string prebody = getPreBody(txn); + TSIOBufferWrite(data->output_buffer.get(), prebody.data(), prebody.length()); // write prebody data->wrote_prebody = true; data->nbytes += prebody.length(); } @@ -127,7 +111,7 @@ body_transform(TSCont contp, TSEvent event, void *edata) if (!src_buf) { // upstream continuation shuts down write operation. data->wrote_body = true; - writePostBody(data); + writePostBody(txn, data); return 0; } @@ -150,7 +134,7 @@ body_transform(TSCont contp, TSEvent event, void *edata) // Write post body content and update output VIO data->wrote_body = true; data->nbytes += TSVIONDoneGet(src_vio); - writePostBody(data); + writePostBody(txn, data); TSContCall(TSVIOContGet(src_vio), TS_EVENT_VCONN_WRITE_COMPLETE, src_vio); } } diff --git a/tests/gold_tests/pluginTest/xdebug/x_remap/four.in b/tests/gold_tests/pluginTest/xdebug/x_remap/four.in index 1982451..6842039 100644 --- a/tests/gold_tests/pluginTest/xdebug/x_remap/four.in +++ b/tests/gold_tests/pluginTest/xdebug/x_remap/four.in @@ -1,4 +1,5 @@ GET /not_there HTTP/1.1 Host: two -X-Debug: X-Remap +X-Debug: X-Remap, Probe +Connection: close diff --git a/tests/gold_tests/pluginTest/xdebug/x_remap/fwd1.in b/tests/gold_tests/pluginTest/xdebug/x_remap/fwd1.in index c67c8ea..82f3fa5 100644 --- a/tests/gold_tests/pluginTest/xdebug/x_remap/fwd1.in +++ b/tests/gold_tests/pluginTest/xdebug/x_remap/fwd1.in @@ -1,4 +1,5 @@ GET /argh HTTP/1.1 Host: two -X-Debug: X-Remap, fwd +X-Debug: X-Remap, fwd, Probe +Connection: close diff --git a/tests/gold_tests/pluginTest/xdebug/x_remap/fwd2.in b/tests/gold_tests/pluginTest/xdebug/x_remap/fwd2.in index 8cb9e7c..4f7ea91 100644 --- a/tests/gold_tests/pluginTest/xdebug/x_remap/fwd2.in +++ b/tests/gold_tests/pluginTest/xdebug/x_remap/fwd2.in @@ -1,4 +1,5 @@ GET /argh HTTP/1.1 Host: two -X-Debug: X-Remap, fwd=0 +X-Debug: X-Remap, fwd=0, probe +Connection: close diff --git a/tests/gold_tests/pluginTest/xdebug/x_remap/fwd3.in b/tests/gold_tests/pluginTest/xdebug/x_remap/fwd3.in index 47402f2..42c187a 100644 --- a/tests/gold_tests/pluginTest/xdebug/x_remap/fwd3.in +++ b/tests/gold_tests/pluginTest/xdebug/x_remap/fwd3.in @@ -1,4 +1,5 @@ GET /argh HTTP/1.1 Host: two -X-Debug: X-Remap, fwd= 1 +X-Debug: X-Remap, fwd= 1, Probe +Connection: close diff --git a/tests/gold_tests/pluginTest/xdebug/x_remap/fwd4.in b/tests/gold_tests/pluginTest/xdebug/x_remap/fwd4.in index 75ca74b..db3ce25 100644 --- a/tests/gold_tests/pluginTest/xdebug/x_remap/fwd4.in +++ b/tests/gold_tests/pluginTest/xdebug/x_remap/fwd4.in @@ -1,4 +1,5 @@ GET /argh HTTP/1.1 Host: two -X-Debug: X-Remap, fwd = 999999 +X-Debug: PROBE, X-Remap, fwd = 999999 +Connection: close diff --git a/tests/gold_tests/pluginTest/xdebug/x_remap/fwd5.in b/tests/gold_tests/pluginTest/xdebug/x_remap/fwd5.in index 3b3e9af..02b44e7 100644 --- a/tests/gold_tests/pluginTest/xdebug/x_remap/fwd5.in +++ b/tests/gold_tests/pluginTest/xdebug/x_remap/fwd5.in @@ -1,4 +1,5 @@ GET /argh HTTP/1.1 Host: two -X-Debug: X-Remap, fwd = 999999xxx +X-Debug: X-Remap, fwd = 999999xxx, Probe +Connection: close diff --git a/tests/gold_tests/pluginTest/xdebug/x_remap/none.in b/tests/gold_tests/pluginTest/xdebug/x_remap/none.in index 6e5b719..a077b72 100644 --- a/tests/gold_tests/pluginTest/xdebug/x_remap/none.in +++ b/tests/gold_tests/pluginTest/xdebug/x_remap/none.in @@ -1,4 +1,5 @@ GET /argh HTTP/1.1 Host: none -X-Debug: X-Remap +X-Debug: X-Remap, Probe +Connection: close diff --git a/tests/gold_tests/pluginTest/xdebug/x_remap/one.in b/tests/gold_tests/pluginTest/xdebug/x_remap/one.in index 48306be..6a35a87 100644 --- a/tests/gold_tests/pluginTest/xdebug/x_remap/one.in +++ b/tests/gold_tests/pluginTest/xdebug/x_remap/one.in @@ -1,4 +1,5 @@ GET /argh HTTP/1.1 Host: one -X-Debug: X-Remap +X-Debug: X-Remap, probe +Connection: close diff --git a/tests/gold_tests/pluginTest/xdebug/x_remap/out.gold b/tests/gold_tests/pluginTest/xdebug/x_remap/out.gold index 0619bd2..4b1e265 100644 --- a/tests/gold_tests/pluginTest/xdebug/x_remap/out.gold +++ b/tests/gold_tests/pluginTest/xdebug/x_remap/out.gold @@ -1,6 +1,6 @@ HTTP/1.1 502 Cannot find server. Date: `` -Connection: keep-alive +Connection: close Server: ATS/`` Cache-Control: no-store Content-Type: text/html @@ -30,10 +30,42 @@ HTTP/1.1 200 OK Date: `` Age: `` Transfer-Encoding: chunked -Connection: keep-alive +Connection: close Server: ATS/`` X-Remap: from=http://one/, to=http://127.0.0.1:SERVER_PORT/ +`` +{'xDebugProbeAt' : '`` + 'captured':[{'type':'request', 'side':'client', 'headers': { + 'Host' : '127.0.0.1:SERVER_PORT', + 'Connection' : 'close', + }},{'type':'request', 'side':'server', 'headers': { + 'Host' : '127.0.0.1:SERVER_PORT', + 'Client-ip' : '127.0.0.1', + 'X-Forwarded-For' : '127.0.0.1', + 'Via' : 'http/1.1 traffic_server[`` + }} + ] +} +--- ATS xDebug Probe Injection Boundary --- + + +--- ATS xDebug Probe Injection Boundary --- + +{'xDebugProbeAt' : '`` + 'captured':[{'type':'response', 'side':'server', 'headers': { + 'Connection' : 'close', + 'Date' : '`` + }},{'type':'response', 'side':'client', 'headers': { + 'Date' : '`` + 'Age' : '0', + 'Transfer-Encoding' : 'chunked', + 'Connection' : 'close', + 'Server' : 'ATS/`` + 'X-Remap' : 'from=http://one/, to=http://127.0.0.1:SERVER_PORT/', + }} + ] +} 0 ====== @@ -41,10 +73,42 @@ HTTP/1.1 200 OK Date: `` Age: `` Transfer-Encoding: chunked -Connection: keep-alive +Connection: close Server: ATS/`` X-Remap: from=http://two/, to=http://127.0.0.1:SERVER_PORT/ +`` +{'xDebugProbeAt' : '`` + 'captured':[{'type':'request', 'side':'client', 'headers': { + 'Host' : '127.0.0.1:SERVER_PORT', + 'Connection' : 'close', + }},{'type':'request', 'side':'server', 'headers': { + 'Host' : '127.0.0.1:SERVER_PORT', + 'Client-ip' : '127.0.0.1', + 'X-Forwarded-For' : '127.0.0.1', + 'Via' : 'http/1.1 traffic_server[`` + }} + ] +} +--- ATS xDebug Probe Injection Boundary --- + + +--- ATS xDebug Probe Injection Boundary --- + +{'xDebugProbeAt' : '`` + 'captured':[{'type':'response', 'side':'server', 'headers': { + 'Connection' : 'close', + 'Date' : '`` + }},{'type':'response', 'side':'client', 'headers': { + 'Date' : '`` + 'Age' : '0', + 'Transfer-Encoding' : 'chunked', + 'Connection' : 'close', + 'Server' : 'ATS/`` + 'X-Remap' : 'from=http://two/, to=http://127.0.0.1:SERVER_PORT/', + }} + ] +} 0 ====== @@ -52,10 +116,42 @@ HTTP/1.1 200 OK Date: `` Age: `` Transfer-Encoding: chunked -Connection: keep-alive +Connection: close Server: ATS/`` X-Remap: from=http://three[0-9]+/, to=http://127.0.0.1:SERVER_PORT/ +`` +{'xDebugProbeAt' : '`` + 'captured':[{'type':'request', 'side':'client', 'headers': { + 'Host' : '127.0.0.1:SERVER_PORT', + 'Connection' : 'close', + }},{'type':'request', 'side':'server', 'headers': { + 'Host' : '127.0.0.1:SERVER_PORT', + 'Client-ip' : '127.0.0.1', + 'X-Forwarded-For' : '127.0.0.1', + 'Via' : 'http/1.1 traffic_server[`` + }} + ] +} +--- ATS xDebug Probe Injection Boundary --- + + +--- ATS xDebug Probe Injection Boundary --- + +{'xDebugProbeAt' : '`` + 'captured':[{'type':'response', 'side':'server', 'headers': { + 'Connection' : 'close', + 'Date' : '`` + }},{'type':'response', 'side':'client', 'headers': { + 'Date' : '`` + 'Age' : '0', + 'Transfer-Encoding' : 'chunked', + 'Connection' : 'close', + 'Server' : 'ATS/`` + 'X-Remap' : 'from=http://three[0-9]+/, to=http://127.0.0.1:SERVER_PORT/', + }} + ] +} 0 ====== @@ -64,9 +160,42 @@ Server: ATS/`` Date: `` Age: `` Transfer-Encoding: chunked -Connection: keep-alive +Connection: close X-Remap: from=http://two/, to=http://127.0.0.1:SERVER_PORT/ +`` +{'xDebugProbeAt' : '`` + 'captured':[{'type':'request', 'side':'client', 'headers': { + 'Host' : '127.0.0.1:SERVER_PORT', + 'Connection' : 'close', + }},{'type':'request', 'side':'server', 'headers': { + 'Host' : '127.0.0.1:SERVER_PORT', + 'Client-ip' : '127.0.0.1', + 'X-Forwarded-For' : '127.0.0.1', + 'Via' : 'http/1.1 traffic_server[`` + }} + ] +} +--- ATS xDebug Probe Injection Boundary --- + + +--- ATS xDebug Probe Injection Boundary --- + +{'xDebugProbeAt' : '`` + 'captured':[{'type':'response', 'side':'server', 'headers': { + 'Server' : 'MicroServer', + 'Connection' : 'close', + 'Date' : '`` + }},{'type':'response', 'side':'client', 'headers': { + 'Server' : 'ATS/`` + 'Date' : '`` + 'Age' : '0', + 'Transfer-Encoding' : 'chunked', + 'Connection' : 'close', + 'X-Remap' : 'from=http://two/, to=http://127.0.0.1:SERVER_PORT/', + }} + ] +} 0 ====== @@ -74,10 +203,44 @@ HTTP/1.1 200 OK Date: `` Age: `` Transfer-Encoding: chunked -Connection: keep-alive +Connection: close Server: ATS/`` X-Remap: from=http://two/, to=http://127.0.0.1:SERVER_PORT/ +`` +{'xDebugProbeAt' : '`` + 'captured':[{'type':'request', 'side':'client', 'headers': { + 'Host' : '127.0.0.1:SERVER_PORT', + 'X-Debug' : 'X-Remap, fwd, Probe', + 'Connection' : 'close', + }},{'type':'request', 'side':'server', 'headers': { + 'Host' : '127.0.0.1:SERVER_PORT', + 'X-Debug' : 'X-Remap, fwd, Probe', + 'Client-ip' : '127.0.0.1', + 'X-Forwarded-For' : '127.0.0.1', + 'Via' : 'http/1.1 traffic_server[`` + }} + ] +} +--- ATS xDebug Probe Injection Boundary --- + + +--- ATS xDebug Probe Injection Boundary --- + +{'xDebugProbeAt' : '`` + 'captured':[{'type':'response', 'side':'server', 'headers': { + 'Connection' : 'close', + 'Date' : '`` + }},{'type':'response', 'side':'client', 'headers': { + 'Date' : '`` + 'Age' : '0', + 'Transfer-Encoding' : 'chunked', + 'Connection' : 'close', + 'Server' : 'ATS/`` + 'X-Remap' : 'from=http://two/, to=http://127.0.0.1:SERVER_PORT/', + }} + ] +} 0 ====== @@ -85,10 +248,42 @@ HTTP/1.1 200 OK Date: `` Age: `` Transfer-Encoding: chunked -Connection: keep-alive +Connection: close Server: ATS/`` X-Remap: from=http://two/, to=http://127.0.0.1:SERVER_PORT/ +`` +{'xDebugProbeAt' : '`` + 'captured':[{'type':'request', 'side':'client', 'headers': { + 'Host' : '127.0.0.1:SERVER_PORT', + 'Connection' : 'close', + }},{'type':'request', 'side':'server', 'headers': { + 'Host' : '127.0.0.1:SERVER_PORT', + 'Client-ip' : '127.0.0.1', + 'X-Forwarded-For' : '127.0.0.1', + 'Via' : 'http/1.1 traffic_server[`` + }} + ] +} +--- ATS xDebug Probe Injection Boundary --- + + +--- ATS xDebug Probe Injection Boundary --- + +{'xDebugProbeAt' : '`` + 'captured':[{'type':'response', 'side':'server', 'headers': { + 'Connection' : 'close', + 'Date' : '`` + }},{'type':'response', 'side':'client', 'headers': { + 'Date' : '`` + 'Age' : '0', + 'Transfer-Encoding' : 'chunked', + 'Connection' : 'close', + 'Server' : 'ATS/`` + 'X-Remap' : 'from=http://two/, to=http://127.0.0.1:SERVER_PORT/', + }} + ] +} 0 ====== @@ -96,10 +291,44 @@ HTTP/1.1 200 OK Date: `` Age: `` Transfer-Encoding: chunked -Connection: keep-alive +Connection: close Server: ATS/`` X-Remap: from=http://two/, to=http://127.0.0.1:SERVER_PORT/ +`` +{'xDebugProbeAt' : '`` + 'captured':[{'type':'request', 'side':'client', 'headers': { + 'Host' : '127.0.0.1:SERVER_PORT', + 'X-Debug' : 'X-Remap, fwd=0, Probe', + 'Connection' : 'close', + }},{'type':'request', 'side':'server', 'headers': { + 'Host' : '127.0.0.1:SERVER_PORT', + 'X-Debug' : 'X-Remap, fwd=0, Probe', + 'Client-ip' : '127.0.0.1', + 'X-Forwarded-For' : '127.0.0.1', + 'Via' : 'http/1.1 traffic_server[`` + }} + ] +} +--- ATS xDebug Probe Injection Boundary --- + + +--- ATS xDebug Probe Injection Boundary --- + +{'xDebugProbeAt' : '`` + 'captured':[{'type':'response', 'side':'server', 'headers': { + 'Connection' : 'close', + 'Date' : '`` + }},{'type':'response', 'side':'client', 'headers': { + 'Date' : '`` + 'Age' : '0', + 'Transfer-Encoding' : 'chunked', + 'Connection' : 'close', + 'Server' : 'ATS/`` + 'X-Remap' : 'from=http://two/, to=http://127.0.0.1:SERVER_PORT/', + }} + ] +} 0 ====== @@ -107,10 +336,44 @@ HTTP/1.1 200 OK Date: `` Age: `` Transfer-Encoding: chunked -Connection: keep-alive +Connection: close Server: ATS/`` X-Remap: from=http://two/, to=http://127.0.0.1:SERVER_PORT/ +`` +{'xDebugProbeAt' : '`` + 'captured':[{'type':'request', 'side':'client', 'headers': { + 'Host' : '127.0.0.1:SERVER_PORT', + 'X-Debug' : 'PROBE, X-Remap, fwd=999998', + 'Connection' : 'close', + }},{'type':'request', 'side':'server', 'headers': { + 'Host' : '127.0.0.1:SERVER_PORT', + 'X-Debug' : 'PROBE, X-Remap, fwd=999998', + 'Client-ip' : '127.0.0.1', + 'X-Forwarded-For' : '127.0.0.1', + 'Via' : 'http/1.1 traffic_server[`` + }} + ] +} +--- ATS xDebug Probe Injection Boundary --- + + +--- ATS xDebug Probe Injection Boundary --- + +{'xDebugProbeAt' : '`` + 'captured':[{'type':'response', 'side':'server', 'headers': { + 'Connection' : 'close', + 'Date' : '`` + }},{'type':'response', 'side':'client', 'headers': { + 'Date' : '`` + 'Age' : '0', + 'Transfer-Encoding' : 'chunked', + 'Connection' : 'close', + 'Server' : 'ATS/`` + 'X-Remap' : 'from=http://two/, to=http://127.0.0.1:SERVER_PORT/', + }} + ] +} 0 ====== @@ -118,10 +381,42 @@ HTTP/1.1 200 OK Date: `` Age: `` Transfer-Encoding: chunked -Connection: keep-alive +Connection: close Server: ATS/`` X-Remap: from=http://two/, to=http://127.0.0.1:SERVER_PORT/ +`` +{'xDebugProbeAt' : '`` + 'captured':[{'type':'request', 'side':'client', 'headers': { + 'Host' : '127.0.0.1:SERVER_PORT', + 'Connection' : 'close', + }},{'type':'request', 'side':'server', 'headers': { + 'Host' : '127.0.0.1:SERVER_PORT', + 'Client-ip' : '127.0.0.1', + 'X-Forwarded-For' : '127.0.0.1', + 'Via' : 'http/1.1 traffic_server[`` + }} + ] +} +--- ATS xDebug Probe Injection Boundary --- + + +--- ATS xDebug Probe Injection Boundary --- + +{'xDebugProbeAt' : '`` + 'captured':[{'type':'response', 'side':'server', 'headers': { + 'Connection' : 'close', + 'Date' : '`` + }},{'type':'response', 'side':'client', 'headers': { + 'Date' : '`` + 'Age' : '0', + 'Transfer-Encoding' : 'chunked', + 'Connection' : 'close', + 'Server' : 'ATS/`` + 'X-Remap' : 'from=http://two/, to=http://127.0.0.1:SERVER_PORT/', + }} + ] +} 0 ====== diff --git a/tests/gold_tests/pluginTest/xdebug/x_remap/three.in b/tests/gold_tests/pluginTest/xdebug/x_remap/three.in index b525bf8..1d9612a 100644 --- a/tests/gold_tests/pluginTest/xdebug/x_remap/three.in +++ b/tests/gold_tests/pluginTest/xdebug/x_remap/three.in @@ -1,4 +1,5 @@ GET /argh HTTP/1.1 Host: three123 -X-Debug: X-Remap +X-Debug: X-Remap, Probe +Connection: close diff --git a/tests/gold_tests/pluginTest/xdebug/x_remap/two.in b/tests/gold_tests/pluginTest/xdebug/x_remap/two.in index c971a91..514d173 100644 --- a/tests/gold_tests/pluginTest/xdebug/x_remap/two.in +++ b/tests/gold_tests/pluginTest/xdebug/x_remap/two.in @@ -1,4 +1,5 @@ GET /argh HTTP/1.1 Host: two -X-Debug: X-Remap +X-Debug: PROBE, X-Remap +Connection: close diff --git a/tests/gold_tests/pluginTest/xdebug/x_remap/x_remap.gold b/tests/gold_tests/pluginTest/xdebug/x_remap/x_remap.gold index d0baa81..5a1e2fd 100644 --- a/tests/gold_tests/pluginTest/xdebug/x_remap/x_remap.gold +++ b/tests/gold_tests/pluginTest/xdebug/x_remap/x_remap.gold @@ -6,13 +6,13 @@ X_DEBUG MISSING - X_DEBUG MISSING - -X-Remap, fwd +X-Remap, fwd, Probe - X_DEBUG MISSING - -X-Remap, fwd=0 +X-Remap, fwd=0, Probe - -X-Remap, fwd=999998 +PROBE, X-Remap, fwd=999998 - X_DEBUG MISSING - diff --git a/tests/gold_tests/pluginTest/xdebug/x_remap/x_remap.test.py b/tests/gold_tests/pluginTest/xdebug/x_remap/x_remap.test.py index 89db82a..73773d8 100644 --- a/tests/gold_tests/pluginTest/xdebug/x_remap/x_remap.test.py +++ b/tests/gold_tests/pluginTest/xdebug/x_remap/x_remap.test.py @@ -15,13 +15,13 @@ # limitations under the License. Test.Summary = ''' -Test xdebug plugin X-Remap and fwd headers +Test xdebug plugin X-Remap, Probe and fwd headers ''' server = Test.MakeOriginServer("server", options={'--load': (Test.TestDirectory + '/x_remap-observer.py')}) request_header = { - "headers": "GET /argh HTTP/1.1\r\nHost: doesnotmatter\r\n\r\n", "timestamp": "1469733493.993", "body": ""} + "headers": "GET /argh HTTP/1.1\r\nHost: doesnotmatter\r\n\r\n", "timestamp": "1469733493.993", "body": "" } response_header = {"headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", "timestamp": "1469733493.993", "body": ""} server.addResponse("sessionlog.json", request_header, response_header)