| /** @file |
| @section license License |
| |
| 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. |
| */ |
| |
| #include <arpa/inet.h> |
| #include <ts.h> |
| #include <algorithm> |
| #include "ts-cpp11.h" |
| #include "ts-cpp11-headers.h" |
| |
| using namespace ats::api; |
| |
| TSHttpHookID TSHookIDFromHookType(HookType hook); |
| |
| class HookContinuationData { |
| public: |
| GlobalHookCallback callback; |
| HookType hooktype; |
| TSHttpHookID ts_hook_id; |
| }; |
| |
| class ats::api::Transaction { |
| public: |
| TSHttpTxn ts_http_txn_ = NULL; |
| TSCont ts_contp_ = NULL; |
| }; |
| |
| extern "C" void TSPluginInit(int argc, const char *argv[]) { |
| |
| TSPluginRegistrationInfo registration_info; |
| |
| const char *api_version_string = "cpp11api"; |
| |
| registration_info.plugin_name = const_cast<char*>(api_version_string); |
| registration_info.vendor_name = const_cast<char*>(api_version_string); |
| registration_info.support_email = const_cast<char*>(api_version_string); |
| |
| if (TSPluginRegister(TS_SDK_VERSION_3_0, ®istration_info) != TS_SUCCESS) { |
| return; |
| } |
| |
| StringVector arguments; |
| for (int i = 0; i < argc; ++i) { |
| arguments.push_back(std::string(argv[i])); |
| } |
| |
| // Finally we will call the wrapper API registration point |
| PluginRegister(arguments); |
| } |
| |
| TSHttpHookID TSHookIDFromHookType(HookType hook) { |
| switch (hook) { |
| case ats::api::HookType::HOOK_PRE_REMAP: |
| return TS_HTTP_PRE_REMAP_HOOK; |
| break; |
| case ats::api::HookType::HOOK_POST_REMAP: |
| return TS_HTTP_POST_REMAP_HOOK; |
| break; |
| case ats::api::HookType::HOOK_READ_REQUEST_HEADERS: |
| return TS_HTTP_READ_REQUEST_HDR_HOOK; |
| break; |
| case ats::api::HookType::HOOK_READ_RESPONSE_HEADERS: |
| return TS_HTTP_READ_RESPONSE_HDR_HOOK; |
| break; |
| case ats::api::HookType::HOOK_SEND_RESPONSE_HEADERS: |
| return TS_HTTP_SEND_RESPONSE_HDR_HOOK; |
| break; |
| case ats::api::HookType::HOOK_TRANSACTION_START: |
| return TS_HTTP_TXN_START_HOOK; |
| break; |
| case ats::api::HookType::HOOK_TRANSACTION_END: |
| return TS_HTTP_TXN_CLOSE_HOOK; |
| break; |
| } |
| |
| return TS_HTTP_PRE_REMAP_HOOK; |
| } |
| |
| void inline ReenableBasedOnNextState(TSHttpTxn txnp, NextState ns) { |
| switch (ns) { |
| case NextState::HTTP_DONT_CONTINUE: |
| return; |
| break; |
| case NextState::HTTP_ERROR: |
| TSHttpTxnReenable(txnp, static_cast<TSEvent>(TS_EVENT_HTTP_ERROR)); |
| break; |
| case NextState::HTTP_CONTINUE: |
| default: |
| TSHttpTxnReenable(txnp, static_cast<TSEvent>(TS_EVENT_HTTP_CONTINUE)); |
| break; |
| } |
| } |
| |
| std::string printable_sockaddr_ip(sockaddr const * s_sockaddr) { |
| const struct sockaddr_in * s_sockaddr_in = |
| reinterpret_cast<const struct sockaddr_in *>(s_sockaddr); |
| |
| char res[INET_ADDRSTRLEN]; |
| inet_ntop(AF_INET, &s_sockaddr_in->sin_addr, res, INET_ADDRSTRLEN); |
| |
| return std::string(res); |
| } |
| |
| std::string ats::api::GetPristineRequestUrl(Transaction &t) { |
| TSMBuffer bufp; |
| TSMLoc url_loc; |
| |
| if (TSHttpTxnPristineUrlGet(t.ts_http_txn_, &bufp, &url_loc) != TS_SUCCESS) |
| return std::string(); |
| |
| int url_len; |
| char *urlp = TSUrlStringGet(bufp, url_loc, &url_len); |
| std::string url(urlp, url_len); |
| |
| TSfree(urlp); |
| |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, url_loc); |
| |
| return url; |
| } |
| |
| std::string ats::api::GetRequestUrl(Transaction &t) { |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| TSMLoc url_loc; |
| |
| if (TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS) |
| return std::string(); |
| |
| TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc); |
| |
| int url_len; |
| char *urlp = TSUrlStringGet(bufp, url_loc, &url_len); |
| std::string url(urlp, url_len); |
| |
| TSfree(urlp); |
| |
| TSHandleMLocRelease(bufp, hdr_loc, url_loc); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| |
| return url; |
| } |
| |
| std::string ats::api::GetRequestUrlScheme(Transaction &t) { |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| TSMLoc url_loc; |
| |
| if (TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS) |
| return std::string(); |
| |
| TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc); |
| |
| int scheme_length; |
| const char *scheme = TSUrlSchemeGet(bufp, url_loc, &scheme_length); |
| |
| std::string ret(scheme, scheme_length); |
| |
| TSHandleMLocRelease(bufp, hdr_loc, url_loc); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| |
| return ret; |
| } |
| |
| |
| std::string ats::api::GetPristineRequestUrlScheme(Transaction &t) { |
| TSMBuffer bufp; |
| TSMLoc url_loc; |
| |
| TSHttpTxnPristineUrlGet(t.ts_http_txn_, &bufp, &url_loc); |
| |
| int length; |
| const char *scheme = TSUrlHostGet(bufp, url_loc, &length); |
| |
| std::string ret(scheme, length); |
| |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, url_loc); |
| |
| return ret; |
| } |
| |
| void ats::api::SetRequestUrlScheme(Transaction &t, const std::string &scheme) { |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| TSMLoc url_loc; |
| |
| TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc); |
| TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc); |
| |
| TSUrlHostSet(bufp, url_loc, scheme.c_str(), scheme.length()); |
| |
| TSHandleMLocRelease(bufp, hdr_loc, url_loc); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } |
| |
| |
| std::string ats::api::GetRequestUrlQuery(Transaction &t) { |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| TSMLoc url_loc; |
| |
| if (TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS) |
| return std::string(); |
| |
| TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc); |
| |
| int query_length; |
| const char *query = TSUrlHttpQueryGet(bufp, url_loc, &query_length); |
| |
| std::string ret(query, query_length); |
| |
| TSHandleMLocRelease(bufp, hdr_loc, url_loc); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| |
| return ret; |
| } |
| |
| std::string ats::api::GetPristineRequestUrlQuery(Transaction &t) { |
| TSMBuffer bufp; |
| TSMLoc url_loc; |
| |
| TSHttpTxnPristineUrlGet(t.ts_http_txn_, &bufp, &url_loc); |
| |
| int query_length; |
| const char *query = TSUrlHostGet(bufp, url_loc, &query_length); |
| |
| std::string ret(query, query_length); |
| |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, url_loc); |
| |
| return ret; |
| } |
| |
| void ats::api::SetRequestUrlQuery(Transaction &t, const std::string &query) { |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| TSMLoc url_loc; |
| |
| TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc); |
| TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc); |
| |
| TSUrlHostSet(bufp, url_loc, query.c_str(), query.length()); |
| |
| TSHandleMLocRelease(bufp, hdr_loc, url_loc); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } |
| |
| std::string ats::api::GetRequestUrlHost(Transaction &t) { |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| TSMLoc url_loc; |
| |
| if (TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS) |
| return std::string(); |
| |
| TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc); |
| |
| int host_length; |
| const char *host = TSUrlHostGet(bufp, url_loc, &host_length); |
| |
| std::string ret(host, host_length); |
| |
| TSHandleMLocRelease(bufp, hdr_loc, url_loc); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| |
| return ret; |
| } |
| |
| std::string ats::api::GetPristineRequestUrlHost(Transaction &t) { |
| TSMBuffer bufp; |
| TSMLoc url_loc; |
| |
| TSHttpTxnPristineUrlGet(t.ts_http_txn_, &bufp, &url_loc); |
| |
| int host_length; |
| const char *host = TSUrlHostGet(bufp, url_loc, &host_length); |
| |
| std::string ret(host, host_length); |
| |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, url_loc); |
| |
| return ret; |
| } |
| |
| void ats::api::SetRequestUrlHost(Transaction &t, const std::string &host) { |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| TSMLoc url_loc; |
| |
| TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc); |
| TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc); |
| |
| TSUrlHostSet(bufp, url_loc, host.c_str(), host.length()); |
| |
| |
| TSHandleMLocRelease(bufp, hdr_loc, url_loc); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } |
| |
| std::string ats::api::GetRequestUrlPath(Transaction &t) { |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| TSMLoc url_loc; |
| |
| if (TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS) |
| return std::string(); |
| |
| TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc); |
| |
| int path_length; |
| const char *path = TSUrlPathGet(bufp, url_loc, &path_length); |
| |
| std::string ret(path, path_length); |
| |
| TSHandleMLocRelease(bufp, hdr_loc, url_loc); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| |
| return ret; |
| } |
| |
| unsigned int ats::api::GetRequestUrlPort(Transaction &t) { |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| TSMLoc url_loc; |
| |
| TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc); |
| TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc); |
| int port = TSUrlPortGet(bufp, url_loc); |
| |
| TSHandleMLocRelease(bufp, hdr_loc, url_loc); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| |
| return port; |
| } |
| |
| unsigned int ats::api::GetPristineRequestUrlPort(Transaction &t) { |
| TSMBuffer bufp; |
| TSMLoc url_loc; |
| |
| TSHttpTxnPristineUrlGet(t.ts_http_txn_, &bufp, &url_loc); |
| int port = TSUrlPortGet(bufp, url_loc); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, url_loc); // TODO: is this wrong? |
| |
| return port; |
| } |
| |
| void ats::api::SetRequestUrlPort(Transaction &t, unsigned int port) { |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| TSMLoc url_loc; |
| |
| TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc); |
| TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc); |
| |
| TSUrlPortSet(bufp, url_loc, port); |
| |
| TSHandleMLocRelease(bufp, hdr_loc, url_loc); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } |
| |
| std::string ats::api::GetPristineRequestUrlPath(Transaction &t) { |
| TSMBuffer bufp; |
| TSMLoc url_loc; |
| |
| TSHttpTxnPristineUrlGet(t.ts_http_txn_, &bufp, &url_loc); |
| |
| int path_length; |
| const char *path = TSUrlPathGet(bufp, url_loc, &path_length); |
| |
| std::string ret(path, path_length); |
| |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, url_loc); |
| |
| return ret; |
| } |
| |
| void ats::api::SetRequestUrlPath(Transaction &t, const std::string &path) { |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| TSMLoc url_loc; |
| |
| TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc); |
| TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc); |
| |
| TSUrlPathSet(bufp, url_loc, path.c_str(), path.length()); |
| |
| TSHandleMLocRelease(bufp, hdr_loc, url_loc); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } |
| |
| static int GlobalContinuationHandler(TSCont contp, TSEvent /* event ATS_UNUSED */, void *edata) { |
| TSHttpTxn txnp = static_cast<TSHttpTxn>(edata); |
| |
| Transaction transaction; |
| transaction.ts_http_txn_ = txnp; |
| transaction.ts_contp_ = contp; |
| |
| HookContinuationData *data = static_cast<HookContinuationData*>(TSContDataGet( |
| contp)); |
| |
| ats::api::NextState ns = data->callback(transaction); |
| ReenableBasedOnNextState(txnp, ns); |
| |
| return 0; |
| } |
| |
| std::string ats::api::GetClientIP(Transaction &t) { |
| return printable_sockaddr_ip(TSHttpTxnClientAddrGet(t.ts_http_txn_)); |
| } |
| |
| unsigned int ats::api::GetClientPort(Transaction &t) { |
| const struct sockaddr_in * client_sockaddr = |
| reinterpret_cast<const struct sockaddr_in *>(TSHttpTxnClientAddrGet( |
| t.ts_http_txn_)); |
| |
| return static_cast<unsigned int>(ntohs(client_sockaddr->sin_port)); |
| } |
| |
| std::string ats::api::GetServerIncomingIP(Transaction &t) { |
| return printable_sockaddr_ip(TSHttpTxnIncomingAddrGet(t.ts_http_txn_)); |
| } |
| |
| unsigned int ats::api::GetServerIncomingPort(Transaction &t) { |
| const struct sockaddr_in * client_sockaddr = |
| reinterpret_cast<const struct sockaddr_in *>(TSHttpTxnIncomingAddrGet( |
| t.ts_http_txn_)); |
| |
| return static_cast<unsigned int>(ntohs(client_sockaddr->sin_port)); |
| } |
| |
| bool ats::api::IsInternalRequest(Transaction &t) { |
| return TSHttpIsInternalRequest(t.ts_http_txn_) == TS_SUCCESS; |
| } |
| |
| int ats::api::GetServerResponseStatusCode(Transaction &t) { |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| |
| TSHttpTxnServerRespGet(t.ts_http_txn_, &bufp, &hdr_loc); |
| int status = TSHttpHdrStatusGet(bufp, hdr_loc); |
| |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| |
| return status; |
| } |
| |
| std::string ats::api::GetRequestMethod(Transaction &t) { |
| |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| |
| TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc); |
| |
| int method_len; |
| const char *methodp = TSHttpHdrMethodGet(bufp, hdr_loc, &method_len); |
| std::string method(methodp, method_len); |
| |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| |
| return method; |
| } |
| |
| void ats::api::SetRequestMethod(Transaction &t, const std::string &method) { |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| |
| TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc); |
| |
| TSHttpHdrMethodSet(bufp, hdr_loc, method.c_str(), method.length()); |
| |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } |
| |
| void ats::api::ReenableTransaction(Transaction &t, NextState ns) { |
| ReenableBasedOnNextState(t.ts_http_txn_, ns); |
| } |
| |
| static int TransactionContinuationHandler(TSCont contp, TSEvent event, |
| void *edata) { |
| TSHttpTxn txnp = static_cast<TSHttpTxn>(edata); |
| |
| Transaction transaction; |
| transaction.ts_http_txn_ = txnp; |
| transaction.ts_contp_ = contp; |
| |
| NextState ns = NextState::HTTP_CONTINUE; |
| HookContinuationData *data = static_cast<HookContinuationData*>(TSContDataGet( |
| contp)); |
| if (event != TS_EVENT_HTTP_TXN_CLOSE |
| || (event == TS_EVENT_HTTP_TXN_CLOSE |
| && data->ts_hook_id == TS_HTTP_TXN_CLOSE_HOOK)) { |
| ns = data->callback(transaction); |
| } |
| |
| // We must free the HookContinuationData structure and continuation |
| // If this transaction is complete |
| if (event == TS_EVENT_HTTP_TXN_CLOSE) { |
| delete data; |
| TSContDestroy(contp); |
| } |
| |
| ReenableBasedOnNextState(txnp, ns); |
| return 0; |
| } |
| |
| void* ats::api::GetTransactionIdentifier(Transaction &t) { |
| return reinterpret_cast<void *>(t.ts_http_txn_); |
| } |
| |
| void ats::api::CreateTransactionHook(Transaction &txn,HookType hook, |
| GlobalHookCallback callback) { |
| TSHttpHookID ts_hook_id = TSHookIDFromHookType(hook); |
| TSCont contp = TSContCreate(TransactionContinuationHandler, NULL); |
| |
| HookContinuationData *data = new HookContinuationData(); |
| data->callback = callback; |
| data->hooktype = hook; |
| data->ts_hook_id = ts_hook_id; |
| |
| TSContDataSet(contp, static_cast<void*>(data)); |
| TSHttpTxnHookAdd(txn.ts_http_txn_, ts_hook_id, contp); |
| |
| if (ts_hook_id != TS_HTTP_TXN_CLOSE_HOOK) { |
| TSHttpTxnHookAdd(txn.ts_http_txn_, TS_HTTP_TXN_CLOSE_HOOK, contp); |
| } |
| } |
| |
| void ats::api::CreateGlobalHook(HookType hook, GlobalHookCallback callback) { |
| |
| TSHttpHookID ts_hook_id = TSHookIDFromHookType(hook); |
| TSCont contp = TSContCreate(GlobalContinuationHandler, NULL); |
| |
| HookContinuationData *data = new HookContinuationData(); |
| data->callback = callback; |
| data->hooktype = hook; |
| |
| TSContDataSet(contp, static_cast<void*>(data)); |
| TSHttpHookAdd(ts_hook_id, contp); |
| } |
| |
| /* |
| * Header code |
| */ |
| |
| void SetHeader(TSMBuffer bufp, TSMLoc hdr_loc, const std::string &name, |
| const std::vector<std::string> &values) { |
| |
| TSMLoc field_loc; |
| |
| field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, name.c_str(), name.length()); |
| |
| // if the field already existed, let's just blow it away. |
| if (field_loc) { |
| TSMimeHdrFieldDestroy(bufp, hdr_loc, field_loc); |
| TSHandleMLocRelease(bufp, hdr_loc, field_loc); |
| } |
| |
| // Now it definitely doesn't exist, so add it. |
| TSMimeHdrFieldCreate(bufp, hdr_loc, &field_loc); |
| TSMimeHdrFieldNameSet(bufp, hdr_loc, field_loc, name.c_str(), name.length()); |
| |
| for (unsigned int i = 0; i < values.size(); ++i) { |
| TSMimeHdrFieldValueStringInsert(bufp, hdr_loc, field_loc, 0, values[i].c_str(), |
| values[i].length()); |
| TSMimeHdrFieldAppend(bufp, hdr_loc, field_loc); |
| } |
| |
| TSHandleMLocRelease(bufp, hdr_loc, field_loc); |
| } |
| |
| void AppendHeader(TSMBuffer bufp, TSMLoc hdr_loc, const std::string &name, |
| const std::vector<std::string> &values) { |
| |
| TSMLoc field_loc; |
| |
| TSMimeHdrFieldCreate(bufp, hdr_loc, &field_loc); |
| TSMimeHdrFieldNameSet(bufp, hdr_loc, field_loc, name.c_str(), name.length()); |
| |
| for (unsigned int i = 0; i < values.size(); ++i) { |
| TSMimeHdrFieldValueStringInsert(bufp, hdr_loc, field_loc, 0, values[i].c_str(), |
| values[i].length()); |
| TSMimeHdrFieldAppend(bufp, hdr_loc, field_loc); |
| } |
| |
| TSHandleMLocRelease(bufp, hdr_loc, field_loc); |
| } |
| |
| void DeleteHeader(TSMBuffer bufp, TSMLoc hdr_loc, const std::string &name) { |
| TSMLoc field_loc; |
| |
| field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, name.c_str(), name.length()); |
| |
| if (field_loc) { |
| TSMimeHdrFieldDestroy(bufp, hdr_loc, field_loc); |
| TSHandleMLocRelease(bufp, hdr_loc, field_loc); |
| } |
| } |
| |
| /* |
| * Obviously this should be optimized to either fill in a passed vector |
| * or just returned a shared_ptr to the build vector, this is an exercise |
| * left to the reader. |
| */ |
| ats::api::headers::HeaderVector GetHeaders(TSMBuffer bufp, TSMLoc hdr_loc) { |
| |
| TSMLoc field_loc; |
| |
| ats::api::headers::HeaderVector hv; |
| |
| field_loc = TSMimeHdrFieldGet(bufp, hdr_loc, 0); |
| while (field_loc) { |
| /* copy the header to a more friedly data structure */ |
| int name_length; |
| const char *fieldName = TSMimeHdrFieldNameGet(bufp, hdr_loc, field_loc, &name_length); |
| |
| ats::api::headers::Header hdr; |
| hdr.assignName(fieldName, name_length); |
| |
| /* now we have to walk all the values and add them */ |
| int numValues = TSMimeHdrFieldValuesCount(bufp, hdr_loc, field_loc); |
| for (int indx = 0; indx < numValues; ++indx) { |
| int val_length; |
| const char *value = TSMimeHdrFieldValueStringGet(bufp, hdr_loc, field_loc, indx, &val_length); |
| hdr.addNewValue(value, val_length); |
| } |
| |
| hv.push_back(hdr); |
| |
| /* Get the next field and release the current one */ |
| TSMLoc next_field_loc = TSMimeHdrFieldNext(bufp, hdr_loc, field_loc); |
| TSHandleMLocRelease(bufp, hdr_loc, field_loc); |
| field_loc = next_field_loc; |
| } |
| |
| return hv; |
| } |
| |
| /* |
| * TODO: All of these can be improved by caching and then invalidating the |
| * header cache when a delete, append, or set occurs. |
| */ |
| |
| void ats::api::headers::DeleteClientRequestHeader(Transaction &t, const std::string &name) { |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| |
| if (TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS) |
| return; |
| |
| DeleteHeader(bufp, hdr_loc, name); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } |
| |
| void ats::api::headers::DeleteClientResponseHeader(Transaction &t, const std::string &name) { |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| |
| if (TSHttpTxnClientRespGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS) |
| return; |
| |
| DeleteHeader(bufp, hdr_loc, name); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } |
| |
| void ats::api::headers::DeleteServerResponseHeader(Transaction &t, const std::string &name) { |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| |
| if (TSHttpTxnServerRespGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS) |
| return; |
| |
| DeleteHeader(bufp, hdr_loc, name); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } |
| |
| void ats::api::headers::SetClientRequestHeader(Transaction &t, const std::string &name, |
| const std::vector<std::string> &vals) { |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| |
| if (TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS) |
| return; |
| |
| SetHeader(bufp, hdr_loc, name, vals); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } |
| |
| void ats::api::headers::SetClientRequestHeader(Transaction &t, const std::string &name, const std::string &val) { |
| |
| std::vector<std::string> vals; |
| vals.push_back(val); |
| SetClientRequestHeader(t, name, vals); |
| } |
| |
| void ats::api::headers::SetClientResponseHeader(Transaction &t, const std::string &name, |
| const std::vector<std::string> &vals) { |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| |
| if (TSHttpTxnClientRespGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS) |
| return; |
| |
| SetHeader(bufp, hdr_loc, name, vals); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } |
| |
| void ats::api::headers::SetClientResponseHeader(Transaction &t, const std::string &name, const std::string &val) { |
| |
| std::vector<std::string> vals; |
| vals.push_back(val); |
| SetClientResponseHeader(t, name, vals); |
| } |
| |
| void ats::api::headers::SetServerResponseHeader(Transaction &t, const std::string &name, |
| const std::vector<std::string> &vals) { |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| |
| if (TSHttpTxnServerRespGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS) |
| return; |
| |
| SetHeader(bufp, hdr_loc, name, vals); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } |
| |
| void ats::api::headers::SetServerResponseHeader(Transaction &t, const std::string &name, const std::string &val) { |
| |
| std::vector<std::string> vals; |
| vals.push_back(val); |
| SetServerResponseHeader(t, name, vals); |
| } |
| |
| void ats::api::headers::AppendServerResponseHeader(Transaction &t, const std::string &name, |
| const std::vector<std::string> &vals) { |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| |
| if (TSHttpTxnServerRespGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS) |
| return; |
| |
| AppendHeader(bufp, hdr_loc, name, vals); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } |
| |
| void ats::api::headers::AppendServerResponseHeader(Transaction &t, const std::string &name, |
| const std::string &val) { |
| |
| std::vector<std::string> vals; |
| vals.push_back(val); |
| AppendServerResponseHeader(t, name, vals); |
| } |
| |
| void ats::api::headers::AppendClientRequestHeader(Transaction &t, const std::string &name, |
| const std::vector<std::string> &vals) { |
| |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| |
| if (TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS) |
| return; |
| |
| AppendHeader(bufp, hdr_loc, name, vals); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } |
| |
| void ats::api::headers::AppendClientRequestHeader(Transaction &t, const std::string &name, |
| const std::string &val) { |
| |
| std::vector<std::string> vals; |
| vals.push_back(val); |
| AppendClientRequestHeader(t, name, vals); |
| } |
| |
| void ats::api::headers::AppendClientResponseHeader(Transaction &t, const std::string &name, |
| const std::vector<std::string> &vals) { |
| |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| |
| if (TSHttpTxnClientRespGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS) |
| return; |
| |
| AppendHeader(bufp, hdr_loc, name, vals); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } |
| |
| void ats::api::headers::AppendClientResponseHeader(Transaction &t, const std::string &name, |
| const std::string &val) { |
| |
| std::vector<std::string> vals; |
| vals.push_back(val); |
| AppendClientResponseHeader(t, name, vals); |
| } |
| |
| ats::api::headers::HeaderVector ats::api::headers::GetClientRequestHeaders(Transaction &t) { |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| |
| HeaderVector hv; |
| |
| if (TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS) |
| return hv; |
| |
| hv = GetHeaders(bufp, hdr_loc); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| |
| return hv; |
| } |
| |
| ats::api::headers::HeaderVector ats::api::headers::GetClientResponseHeaders(Transaction &t) { |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| |
| HeaderVector hv; |
| |
| if (TSHttpTxnClientRespGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS) |
| return hv; |
| |
| hv = GetHeaders(bufp, hdr_loc); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| |
| return hv; |
| } |
| |
| ats::api::headers::HeaderVector ats::api::headers::GetServerResponseHeaders(Transaction &t) { |
| TSMBuffer bufp; |
| TSMLoc hdr_loc; |
| |
| HeaderVector hv; |
| |
| if (TSHttpTxnServerRespGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS) |
| return hv; |
| |
| hv = GetHeaders(bufp, hdr_loc); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| |
| return hv; |
| } |
| |
| inline ats::api::headers::Header GetHeader(Transaction & /* t ATS_UNUSED */, const std::string& hdr_name, |
| const ats::api::headers::HeaderVector &hdrs) { |
| |
| ats::api::headers::Header hdr; |
| ats::api::headers::HeaderVector::const_iterator ii = std::find_if(hdrs.begin(), hdrs.end(), |
| ats::api::headers::HeaderName(hdr_name)); |
| |
| if (ii != hdrs.end()) { |
| hdr = *ii; |
| } |
| |
| return hdr; |
| } |
| |
| ats::api::headers::Header ats::api::headers::GetClientRequestHeader(Transaction &t, const std::string& hdr_name) { |
| return GetHeader(t, hdr_name, GetClientRequestHeaders(t)); |
| } |
| |
| ats::api::headers::Header ats::api::headers::GetClientResponseHeader(Transaction &t, const std::string& hdr_name) { |
| return GetHeader(t, hdr_name, GetClientResponseHeaders(t)); |
| } |
| |
| ats::api::headers::Header ats::api::headers::GetServerResponseHeader(Transaction &t, const std::string& hdr_name) { |
| return GetHeader(t, hdr_name, GetServerResponseHeaders(t)); |
| } |