| /* |
| 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 <deque> |
| #include <map> |
| #include <memory> |
| #include <mutex> |
| #include <unordered_map> |
| #include <unordered_set> |
| |
| #include "ats_context.h" |
| #include "ats_wasm.h" |
| |
| #include "include/proxy-wasm/context.h" |
| #include "include/proxy-wasm/wasm.h" |
| #include "src/shared_data.h" |
| #include "src/shared_queue.h" |
| |
| namespace ats_wasm |
| { |
| |
| DbgCtl dbg_ctl{WASM_DEBUG_TAG}; |
| |
| static int |
| async_handler(TSCont cont, TSEvent event, void *edata) |
| { |
| // information for the handler |
| TSHttpTxn txn = static_cast<TSHttpTxn>(edata); |
| AsyncInfo *ai = static_cast<AsyncInfo *>(TSContDataGet(cont)); |
| uint32_t token = ai->token; |
| Context *root_context = ai->root_context; |
| Wasm *wasm = root_context->wasm(); |
| |
| // variables to be used in handler |
| TSEvent result = static_cast<TSEvent>(FETCH_EVENT_ID_BASE + 1); |
| const void *body = nullptr; |
| size_t body_size = 0; |
| TSMBuffer hdr_buf = nullptr; |
| TSMLoc hdr_loc = nullptr; |
| int header_size = 0; |
| |
| TSMutexLock(wasm->mutex()); |
| // filling in variables for a successful fetch |
| if (event == static_cast<TSEvent>(FETCH_EVENT_ID_BASE)) { |
| int data_len; |
| const char *data_start = TSFetchRespGet(txn, &data_len); |
| if (data_start && (data_len > 0)) { |
| const char *data_end = data_start + data_len; |
| TSHttpParser parser = TSHttpParserCreate(); |
| hdr_buf = TSMBufferCreate(); |
| hdr_loc = TSHttpHdrCreate(hdr_buf); |
| TSHttpHdrTypeSet(hdr_buf, hdr_loc, TS_HTTP_TYPE_RESPONSE); |
| if (TSHttpHdrParseResp(parser, hdr_buf, hdr_loc, &data_start, data_end) == TS_PARSE_DONE) { |
| TSHttpStatus status = TSHttpHdrStatusGet(hdr_buf, hdr_loc); |
| header_size = TSMimeHdrFieldsCount(hdr_buf, hdr_loc); |
| body = data_start; // data_start will now be pointing to body |
| body_size = data_end - data_start; |
| Dbg(dbg_ctl, "[%s] Fetch result had a status code of %d with a body length of %ld", __FUNCTION__, status, body_size); |
| } else { |
| TSError("[wasm][%s] Unable to parse call response", __FUNCTION__); |
| event = static_cast<TSEvent>(FETCH_EVENT_ID_BASE + 1); |
| } |
| TSHttpParserDestroy(parser); |
| } else { |
| TSError("[wasm][%s] Successful fetch did not result in any content. Assuming failure", __FUNCTION__); |
| event = static_cast<TSEvent>(FETCH_EVENT_ID_BASE + 1); |
| } |
| result = event; |
| } |
| |
| // callback function |
| Dbg(dbg_ctl, "[%s] setting root context call result", __FUNCTION__); |
| root_context->setHttpCallResult(hdr_buf, hdr_loc, body, body_size, result); |
| Dbg(dbg_ctl, "[%s] trigger root context function, token: %d", __FUNCTION__, token); |
| root_context->onHttpCallResponse(token, header_size, body_size, 0); |
| Dbg(dbg_ctl, "[%s] resetting root context call result", __FUNCTION__); |
| root_context->resetHttpCallResult(); |
| |
| // cleaning up |
| if (hdr_loc) { |
| TSMLoc null_parent_loc = nullptr; |
| TSHandleMLocRelease(hdr_buf, null_parent_loc, hdr_loc); |
| } |
| if (hdr_buf) { |
| TSMBufferDestroy(hdr_buf); |
| } |
| |
| TSMutexUnlock(wasm->mutex()); |
| |
| Dbg(dbg_ctl, "[%s] delete async info and continuation", __FUNCTION__); |
| // delete the Async Info |
| delete ai; |
| // delete continuation |
| TSContDestroy(cont); |
| |
| return 0; |
| } |
| |
| // utiltiy function for properties |
| static void |
| print_address(struct sockaddr const *ip, std::string *result) |
| { |
| if (ip != nullptr) { |
| char cip[128] = ""; |
| int64_t port = 0; |
| if (ip->sa_family == AF_INET) { |
| const auto *s_sockaddr_in = reinterpret_cast<const struct sockaddr_in *>(ip); |
| inet_ntop(AF_INET, &s_sockaddr_in->sin_addr, cip, sizeof(cip)); |
| port = s_sockaddr_in->sin_port; |
| } else if (ip->sa_family == AF_INET6) { |
| const auto *s_sockaddr_in6 = reinterpret_cast<const struct sockaddr_in6 *>(ip); |
| inet_ntop(AF_INET6, &s_sockaddr_in6->sin6_addr, cip, sizeof(cip)); |
| port = s_sockaddr_in6->sin6_port; |
| } |
| Dbg(dbg_ctl, "[%s] property retrieval - address: %.*s", __FUNCTION__, static_cast<int>(sizeof(cip)), cip); |
| std::string cip_str(cip); |
| result->assign(cip_str + ":" + std::to_string(port)); |
| } else { |
| *result = pv_empty; |
| } |
| } |
| |
| static void |
| print_port(struct sockaddr const *ip, std::string *result) |
| { |
| if (ip != nullptr) { |
| int64_t port = 0; |
| if (ip->sa_family == AF_INET) { |
| const auto *s_sockaddr_in = reinterpret_cast<const struct sockaddr_in *>(ip); |
| port = s_sockaddr_in->sin_port; |
| } else { |
| const auto *s_sockaddr_in6 = reinterpret_cast<const struct sockaddr_in6 *>(ip); |
| port = s_sockaddr_in6->sin6_port; |
| } |
| Dbg(dbg_ctl, "[%s] looking for source port: %d", __FUNCTION__, static_cast<int>(port)); |
| result->assign(reinterpret_cast<const char *>(&port), sizeof(int64_t)); |
| } else { |
| *result = pv_empty; |
| } |
| } |
| |
| static void |
| print_certificate(std::string *result, X509_NAME *name) |
| { |
| if (name == nullptr) { |
| *result = pv_empty; |
| return; |
| } |
| |
| BIO *bio = BIO_new(BIO_s_mem()); |
| if (bio == nullptr) { |
| *result = pv_empty; |
| return; |
| } |
| |
| if (X509_NAME_print_ex(bio, name, 0 /* indent */, XN_FLAG_ONELINE) > 0) { |
| int64_t len = 0; |
| char *ptr = nullptr; |
| len = BIO_get_mem_data(bio, &ptr); |
| result->assign(ptr, len); |
| Dbg(dbg_ctl, "print SSL certificate %.*s", static_cast<int>(len), ptr); |
| } |
| |
| BIO_free(bio); |
| } |
| |
| static void |
| print_san_certificate(std::string *result, X509 *cert, int type) |
| { |
| int ext_ndx = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1); |
| if (ext_ndx >= 0) { |
| X509_EXTENSION *ext = nullptr; |
| STACK_OF(GENERAL_NAME) *alt_names = nullptr; |
| GENERAL_NAME *gen_name = nullptr; |
| |
| ext = X509_get_ext(cert, ext_ndx); |
| alt_names = static_cast<stack_st_GENERAL_NAME *>(X509V3_EXT_d2i(ext)); |
| if (alt_names != nullptr) { |
| int num = sk_GENERAL_NAME_num(alt_names); |
| bool found = false; |
| for (int i = 0; i < num; i++) { |
| gen_name = sk_GENERAL_NAME_value(alt_names, i); |
| if (gen_name->type == type) { |
| char *dnsname = reinterpret_cast<char *>(ASN1_STRING_data(gen_name->d.dNSName)); |
| int dnsname_len = ASN1_STRING_length(gen_name->d.dNSName); |
| result->assign(dnsname, dnsname_len); |
| found = true; |
| break; |
| } |
| } |
| if (!found) { |
| *result = pv_empty; |
| } |
| sk_GENERAL_NAME_free(alt_names); |
| } else { |
| *result = pv_empty; |
| } |
| } else { |
| *result = pv_empty; |
| } |
| } |
| |
| static bool |
| get_header(TSMBuffer bufp, TSMLoc hdr_loc, std::string_view v, std::string *result) |
| { |
| const char *key = v.data(); |
| int key_len = v.size(); |
| const char *val = nullptr; |
| int val_len = 0; |
| std::string res = ""; |
| TSMLoc field_loc = nullptr; |
| TSMLoc next_field_loc = nullptr; |
| bool found = false; |
| |
| field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, key, key_len); |
| if (field_loc != TS_NULL_MLOC) { |
| while (field_loc != TS_NULL_MLOC) { |
| val = TSMimeHdrFieldValueStringGet(bufp, hdr_loc, field_loc, -1, &val_len); |
| next_field_loc = TSMimeHdrFieldNextDup(bufp, hdr_loc, field_loc); |
| res.append(val, val_len); |
| if (next_field_loc != TS_NULL_MLOC) { |
| res.append(",", 1); |
| } |
| TSHandleMLocRelease(bufp, hdr_loc, field_loc); |
| field_loc = next_field_loc; |
| } |
| found = true; |
| } |
| *result = res; |
| return found; |
| } |
| |
| static void |
| set_header(TSMBuffer bufp, TSMLoc hdr_loc, std::string_view v, std::string_view serialized_value) |
| { |
| bool remove = false; |
| |
| if (serialized_value == "") { |
| remove = true; |
| } |
| |
| TSMLoc field_loc = nullptr; |
| TSMLoc tmp = nullptr; |
| bool first = true; |
| |
| field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, v.data(), v.size()); |
| |
| if (remove) { |
| while (field_loc != TS_NULL_MLOC) { |
| tmp = TSMimeHdrFieldNextDup(bufp, hdr_loc, field_loc); |
| TSMimeHdrFieldDestroy(bufp, hdr_loc, field_loc); |
| TSHandleMLocRelease(bufp, hdr_loc, field_loc); |
| field_loc = tmp; |
| } |
| } else if (field_loc != TS_NULL_MLOC) { |
| first = true; |
| while (field_loc != TS_NULL_MLOC) { |
| tmp = TSMimeHdrFieldNextDup(bufp, hdr_loc, field_loc); |
| if (first) { |
| first = false; |
| TSMimeHdrFieldValueStringSet(bufp, hdr_loc, field_loc, -1, serialized_value.data(), serialized_value.size()); |
| } else { |
| TSMimeHdrFieldDestroy(bufp, hdr_loc, field_loc); |
| } |
| TSHandleMLocRelease(bufp, hdr_loc, field_loc); |
| field_loc = tmp; |
| } |
| } else if (TSMimeHdrFieldCreateNamed(bufp, hdr_loc, v.data(), v.size(), &field_loc) != TS_SUCCESS) { |
| TSError("[wasm][%s] TSMimeHdrFieldCreateNamed error", __FUNCTION__); |
| } else { |
| TSMimeHdrFieldValueStringSet(bufp, hdr_loc, field_loc, -1, serialized_value.data(), serialized_value.size()); |
| TSMimeHdrFieldAppend(bufp, hdr_loc, field_loc); |
| } |
| |
| if (field_loc != TS_NULL_MLOC) { |
| TSHandleMLocRelease(bufp, hdr_loc, field_loc); |
| } |
| } |
| |
| // Buffer copyTo |
| WasmResult |
| Buffer::copyTo(WasmBase *wasm, size_t start, size_t length, uint64_t ptr_ptr, uint64_t size_ptr) const |
| { |
| if (owned_data_str_ != "") { |
| std::string_view s(owned_data_str_); |
| if (!wasm->copyToPointerSize(s, ptr_ptr, size_ptr)) { |
| return WasmResult::InvalidMemoryAccess; |
| } |
| return WasmResult::Ok; |
| } |
| return BufferBase::copyTo(wasm, start, length, ptr_ptr, size_ptr); |
| } |
| |
| Context::Context() : ContextBase() {} |
| |
| Context::Context(Wasm *wasm) : ContextBase(wasm) {} |
| |
| Context::Context(Wasm *wasm, const std::shared_ptr<PluginBase> &plugin) : ContextBase(wasm, plugin) {} |
| |
| // NB: wasm can be nullptr if it failed to be created successfully. |
| Context::Context(Wasm *wasm, uint32_t parent_context_id, const std::shared_ptr<PluginBase> &plugin) : ContextBase(wasm, plugin) |
| { |
| // setting up parent context |
| parent_context_id_ = parent_context_id; |
| if (wasm_ != nullptr) { |
| parent_context_ = wasm_->getContext(parent_context_id_); |
| } |
| } |
| |
| // utility functions for the extended class |
| Wasm * |
| Context::wasm() const |
| { |
| return static_cast<Wasm *>(wasm_); |
| } |
| |
| Context * |
| Context::parent_context() const |
| { |
| return static_cast<Context *>(parent_context_); |
| } |
| |
| Context * |
| Context::root_context() const |
| { |
| const ContextBase *previous = this; |
| ContextBase *parent = parent_context_; |
| while (parent != previous) { |
| previous = parent; |
| parent = parent->parent_context(); |
| } |
| return static_cast<Context *>(parent); |
| } |
| |
| void |
| Context::initialize(TSHttpTxn txnp) |
| { |
| txnp_ = txnp; |
| } |
| |
| void |
| Context::initialize(TSCont cont) |
| { |
| scheduler_cont_ = cont; |
| } |
| |
| TSHttpTxn |
| Context::txnp() |
| { |
| return txnp_; |
| } |
| |
| TSCont |
| Context::scheduler_cont() |
| { |
| return scheduler_cont_; |
| } |
| |
| void |
| Context::error(std::string_view message) |
| { |
| TSError("%.*s", static_cast<int>(message.size()), message.data()); |
| abort(); |
| } |
| |
| // local reply handler |
| void |
| Context::onLocalReply() |
| { |
| if (local_reply_) { |
| if (txnp_ == nullptr) { |
| return; |
| } |
| |
| TSMBuffer bufp = nullptr; |
| TSMLoc hdr_loc = nullptr; |
| if (TSHttpTxnClientRespGet(txnp_, &bufp, &hdr_loc) != TS_SUCCESS) { |
| return; |
| } |
| |
| // set local reply reason |
| if (!local_reply_details_.empty()) { |
| TSHttpHdrReasonSet(bufp, hdr_loc, local_reply_details_.data(), local_reply_details_.size()); |
| } |
| |
| // set local reply headers |
| for (auto &p : local_reply_headers_) { |
| std::string key(p.first); |
| std::string value(p.second); |
| |
| auto *loc = TSMimeHdrFieldFind(bufp, hdr_loc, key.data(), static_cast<int>(key.size())); |
| if (loc != TS_NULL_MLOC) { |
| int first = 1; |
| while (loc != TS_NULL_MLOC) { |
| auto *tmp = TSMimeHdrFieldNextDup(bufp, hdr_loc, loc); |
| if (first != 0) { |
| first = 0; |
| TSMimeHdrFieldValueStringSet(bufp, hdr_loc, loc, -1, value.data(), static_cast<int>(value.size())); |
| } else { |
| TSMimeHdrFieldDestroy(bufp, hdr_loc, loc); |
| } |
| TSHandleMLocRelease(bufp, hdr_loc, loc); |
| loc = tmp; |
| } |
| } else if (TSMimeHdrFieldCreateNamed(bufp, hdr_loc, key.data(), static_cast<int>(key.size()), &loc) != TS_SUCCESS) { |
| TSError("[wasm][%s] TSMimeHdrFieldCreateNamed error", __FUNCTION__); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| return; |
| } else { |
| TSMimeHdrFieldValueStringSet(bufp, hdr_loc, loc, -1, value.data(), static_cast<int>(value.size())); |
| TSMimeHdrFieldAppend(bufp, hdr_loc, loc); |
| } |
| |
| if (loc != TS_NULL_MLOC) { |
| TSHandleMLocRelease(bufp, hdr_loc, loc); |
| } |
| } |
| |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } |
| } |
| |
| // |
| // General functions |
| // |
| WasmResult |
| Context::log(uint32_t level, std::string_view message) |
| { |
| auto l = static_cast<LogLevel>(level); |
| switch (l) { |
| case LogLevel::trace: |
| Dbg(dbg_ctl, "wasm trace log%s: %.*s", std::string(log_prefix()).c_str(), static_cast<int>(message.size()), message.data()); |
| return WasmResult::Ok; |
| case LogLevel::debug: |
| Dbg(dbg_ctl, "wasm debug log%s: %.*s", std::string(log_prefix()).c_str(), static_cast<int>(message.size()), message.data()); |
| return WasmResult::Ok; |
| case LogLevel::info: |
| Dbg(dbg_ctl, "wasm info log%s: %.*s", std::string(log_prefix()).c_str(), static_cast<int>(message.size()), message.data()); |
| return WasmResult::Ok; |
| case LogLevel::warn: |
| Dbg(dbg_ctl, "wasm warn log%s: %.*s", std::string(log_prefix()).c_str(), static_cast<int>(message.size()), message.data()); |
| return WasmResult::Ok; |
| case LogLevel::error: |
| Dbg(dbg_ctl, "wasm error log%s: %.*s", std::string(log_prefix()).c_str(), static_cast<int>(message.size()), message.data()); |
| return WasmResult::Ok; |
| case LogLevel::critical: |
| Dbg(dbg_ctl, "wasm critical log%s: %.*s", std::string(log_prefix()).c_str(), static_cast<int>(message.size()), message.data()); |
| return WasmResult::Ok; |
| default: // e.g. off |
| return unimplemented(); |
| } |
| return unimplemented(); |
| } |
| |
| uint64_t |
| Context::getCurrentTimeNanoseconds() |
| { |
| return TShrtime(); |
| } |
| |
| uint64_t |
| Context::getMonotonicTimeNanoseconds() |
| { |
| return TShrtime(); |
| } |
| |
| std::string_view |
| Context::getConfiguration() |
| { |
| return plugin_->plugin_configuration_; |
| } |
| |
| WasmResult |
| Context::setTimerPeriod(std::chrono::milliseconds period, uint32_t *timer_token_ptr) |
| { |
| Wasm *wasm = this->wasm(); |
| Context *root_context = this->root_context(); |
| TSMutexLock(wasm->mutex()); |
| if (!wasm->existsTimerPeriod(root_context->id())) { |
| Dbg(dbg_ctl, "[%s] no previous timer period set", __FUNCTION__); |
| TSCont contp = root_context->scheduler_cont(); |
| if (contp != nullptr) { |
| Dbg(dbg_ctl, "[%s] scheduling continuation for timer", __FUNCTION__); |
| TSContDataSet(contp, root_context); |
| TSContScheduleOnPool(contp, static_cast<TSHRTime>(period.count()), TS_THREAD_POOL_NET); |
| } |
| } |
| |
| wasm->setTimerPeriod(root_context->id(), period); |
| *timer_token_ptr = 0; |
| TSMutexUnlock(wasm->mutex()); |
| return WasmResult::Ok; |
| } |
| |
| BufferInterface * |
| Context::getBuffer(WasmBufferType type) |
| { |
| switch (type) { |
| case WasmBufferType::VmConfiguration: |
| return buffer_.set(wasm_->vm_configuration()); |
| case WasmBufferType::PluginConfiguration: |
| return buffer_.set(plugin_->plugin_configuration_); |
| case WasmBufferType::HttpCallResponseBody: |
| if (cr_body_ != nullptr) { |
| return buffer_.set(std::string(static_cast<const char *>(cr_body_), cr_body_size_)); |
| } |
| return buffer_.set(""); |
| case WasmBufferType::HttpRequestBody: |
| case WasmBufferType::HttpResponseBody: |
| // return transform result |
| return &transform_result_; |
| case WasmBufferType::CallData: |
| case WasmBufferType::NetworkDownstreamData: |
| case WasmBufferType::NetworkUpstreamData: |
| case WasmBufferType::GrpcReceiveBuffer: |
| default: |
| unimplemented(); |
| return nullptr; |
| } |
| } |
| |
| WasmResult |
| Context::httpCall(std::string_view /* target ATS_UNUSED */, const Pairs &request_headers, std::string_view request_body, |
| const Pairs & /* request_trailers ATS_UNUSED */, int /* timeout_millisconds ATS_UNUSED */, uint32_t *token_ptr) |
| { |
| Wasm *wasm = this->wasm(); |
| Context *root_context = this->root_context(); |
| |
| TSCont contp; |
| std::string request, method, path, authority; |
| |
| // setup local address for API call |
| struct sockaddr_in addr; |
| addr.sin_family = AF_INET; |
| addr.sin_addr.s_addr = LOCAL_IP_ADDRESS; |
| addr.sin_port = LOCAL_PORT; |
| |
| for (const auto &p : request_headers) { |
| std::string key(p.first); |
| std::string value(p.second); |
| |
| if (key == ":method") { |
| method = value; |
| } else if (key == ":path") { |
| path = value; |
| } else if (key == ":authority") { |
| authority = value; |
| } |
| } |
| |
| /* request */ |
| request = method + " https://" + authority + path + " HTTP/1.1\r\n"; |
| for (const auto &p : request_headers) { |
| std::string key(p.first); |
| std::string value(p.second); |
| request += key + ": " + value + "\r\n"; |
| } |
| request += "\r\n"; |
| request += request_body; |
| |
| TSFetchEvent event_ids; |
| event_ids.success_event_id = FETCH_EVENT_ID_BASE; |
| event_ids.failure_event_id = FETCH_EVENT_ID_BASE + 1; |
| event_ids.timeout_event_id = FETCH_EVENT_ID_BASE + 2; |
| |
| contp = TSContCreate(async_handler, TSMutexCreate()); |
| AsyncInfo *ai = new AsyncInfo(); |
| ai->token = wasm->nextHttpCallId(); |
| ai->root_context = root_context; |
| *token_ptr = ai->token; // to be returned to the caller |
| TSContDataSet(contp, ai); |
| |
| // API call for async fetch |
| TSFetchUrl(request.c_str(), request.size(), reinterpret_cast<struct sockaddr const *>(&addr), contp, AFTER_BODY, event_ids); |
| |
| return WasmResult::Ok; |
| } |
| |
| // Metrics |
| WasmResult |
| Context::defineMetric(uint32_t metric_type, std::string_view name, uint32_t *metric_id_ptr) |
| { |
| int idp = 0; |
| TSStatSync ats_metric_type = TS_STAT_SYNC_COUNT; |
| auto type = static_cast<MetricType>(metric_type); |
| switch (type) { |
| case MetricType::Counter: |
| ats_metric_type = TS_STAT_SYNC_COUNT; |
| break; |
| case MetricType::Gauge: |
| ats_metric_type = TS_STAT_SYNC_SUM; |
| break; |
| case MetricType::Histogram: |
| ats_metric_type = TS_STAT_SYNC_AVG; |
| break; |
| default: |
| TSError("[wasm][%s] Invalid metric type", __FUNCTION__); |
| return WasmResult::BadArgument; |
| } |
| |
| if (TSStatFindName(name.data(), &idp) == TS_ERROR) { |
| idp = TSStatCreate(name.data(), TS_RECORDDATATYPE_INT, TS_STAT_PERSISTENT, ats_metric_type); |
| Dbg(dbg_ctl, "[%s] creating stat: %.*s", __FUNCTION__, static_cast<int>(name.size()), name.data()); |
| *metric_id_ptr = idp; |
| } else { |
| TSError("[wasm][%s] Metric already exists", __FUNCTION__); |
| *metric_id_ptr = idp; |
| } |
| |
| return WasmResult::Ok; |
| } |
| |
| WasmResult |
| Context::incrementMetric(uint32_t metric_id, int64_t offset) |
| { |
| TSStatIntIncrement(metric_id, offset); |
| return WasmResult::Ok; |
| } |
| |
| WasmResult |
| Context::recordMetric(uint32_t metric_id, uint64_t value) |
| { |
| TSStatIntSet(metric_id, value); |
| return WasmResult::Ok; |
| } |
| |
| WasmResult |
| Context::getMetric(uint32_t metric_id, uint64_t *value_ptr) |
| { |
| *value_ptr = TSStatIntGet(metric_id); |
| return WasmResult::Ok; |
| } |
| |
| // Properties |
| WasmResult |
| Context::getProperty(std::string_view path, std::string *result) |
| { |
| if (path.substr(0, p_plugin_root_id.size()) == p_plugin_root_id) { |
| *result = this->plugin_->root_id_; |
| Dbg(dbg_ctl, "[%s] looking for plugin_root_id: %.*s", __FUNCTION__, static_cast<int>((*result).size()), (*result).data()); |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_plugin_name.size()) == p_plugin_name) { |
| *result = this->plugin_->name_; |
| Dbg(dbg_ctl, "[%s] looking for plugin_name: %.*s", __FUNCTION__, static_cast<int>((*result).size()), (*result).data()); |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_plugin_vm_id.size()) == p_plugin_vm_id) { |
| *result = this->plugin_->vm_id_; |
| Dbg(dbg_ctl, "[%s] looking for plugin_vm_id: %.*s", __FUNCTION__, static_cast<int>((*result).size()), (*result).data()); |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_node.size()) == p_node) { |
| *result = pv_empty; |
| Dbg(dbg_ctl, "[%s] looking for node property: empty string for now", __FUNCTION__); |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_source_address.size()) == p_source_address) { |
| if (txnp_ == nullptr) { |
| *result = pv_empty; |
| return WasmResult::Ok; |
| } |
| struct sockaddr const *client_ip = nullptr; |
| client_ip = TSHttpTxnClientAddrGet(txnp_); |
| print_address(client_ip, result); |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_source_port.size()) == p_source_port) { |
| if (txnp_ == nullptr) { |
| *result = pv_empty; |
| return WasmResult::Ok; |
| } |
| struct sockaddr const *client_ip = nullptr; |
| client_ip = TSHttpTxnClientAddrGet(txnp_); |
| print_port(client_ip, result); |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_destination_address.size()) == p_destination_address) { |
| if (txnp_ == nullptr) { |
| *result = pv_empty; |
| return WasmResult::Ok; |
| } |
| struct sockaddr const *local_ip = nullptr; |
| local_ip = TSHttpTxnIncomingAddrGet(txnp_); |
| print_address(local_ip, result); |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_destination_port.size()) == p_destination_port) { |
| if (txnp_ == nullptr) { |
| *result = pv_empty; |
| return WasmResult::Ok; |
| } |
| struct sockaddr const *local_ip = nullptr; |
| local_ip = TSHttpTxnIncomingAddrGet(txnp_); |
| print_port(local_ip, result); |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_connection_mtls.size()) == p_connection_mtls) { |
| bool m = false; |
| if (txnp_ == nullptr) { |
| result->assign(reinterpret_cast<const char *>(&m), sizeof(bool)); |
| return WasmResult::Ok; |
| } |
| TSHttpSsn ssnp = TSHttpTxnSsnGet(txnp_); |
| TSVConn client_conn = TSHttpSsnClientVConnGet(ssnp); |
| TSSslConnection sslobj = TSVConnSslConnectionGet(client_conn); |
| SSL *ssl = reinterpret_cast<SSL *>(sslobj); |
| #ifdef OPENSSL_IS_OPENSSL3 |
| X509 *cert = SSL_get1_peer_certificate(ssl); |
| #else |
| X509 *cert = SSL_get_peer_certificate(ssl); |
| #endif |
| if (cert != nullptr) { |
| m = true; |
| X509_free(cert); |
| } |
| result->assign(reinterpret_cast<const char *>(&m), sizeof(bool)); |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_connection_requested_server_name.size()) == p_connection_requested_server_name) { |
| if (txnp_ == nullptr) { |
| *result = pv_empty; |
| return WasmResult::Ok; |
| } |
| TSHttpSsn ssnp = TSHttpTxnSsnGet(txnp_); |
| TSVConn client_conn = TSHttpSsnClientVConnGet(ssnp); |
| TSSslConnection sslobj = TSVConnSslConnectionGet(client_conn); |
| SSL *ssl = reinterpret_cast<SSL *>(sslobj); |
| char const *const sni_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); |
| if (sni_name != nullptr) { |
| result->assign(sni_name); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_connection_tls_version.size()) == p_connection_tls_version) { |
| if (txnp_ == nullptr) { |
| *result = pv_empty; |
| return WasmResult::Ok; |
| } |
| const char *ssl_protocol = "-"; |
| TSHttpSsn ssnp = TSHttpTxnSsnGet(txnp_); |
| TSVConn client_conn = TSHttpSsnClientVConnGet(ssnp); |
| |
| if (TSVConnIsSsl(client_conn) != 0) { |
| ssl_protocol = TSVConnSslProtocolGet(client_conn); |
| } |
| |
| result->assign(ssl_protocol); |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_connection_subject_local_certificate.size()) == p_connection_subject_local_certificate) { |
| if (txnp_ == nullptr) { |
| *result = pv_empty; |
| return WasmResult::Ok; |
| } |
| TSHttpSsn ssnp = TSHttpTxnSsnGet(txnp_); |
| TSVConn client_conn = TSHttpSsnClientVConnGet(ssnp); |
| TSSslConnection sslobj = TSVConnSslConnectionGet(client_conn); |
| SSL *ssl = reinterpret_cast<SSL *>(sslobj); |
| X509 *cert = SSL_get_certificate(ssl); |
| if (cert != nullptr) { |
| print_certificate(result, X509_get_subject_name(cert)); |
| X509_free(cert); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_connection_subject_peer_certificate.size()) == p_connection_subject_peer_certificate) { |
| if (txnp_ == nullptr) { |
| *result = pv_empty; |
| return WasmResult::Ok; |
| } |
| TSHttpSsn ssnp = TSHttpTxnSsnGet(txnp_); |
| TSVConn client_conn = TSHttpSsnClientVConnGet(ssnp); |
| TSSslConnection sslobj = TSVConnSslConnectionGet(client_conn); |
| SSL *ssl = reinterpret_cast<SSL *>(sslobj); |
| #ifdef OPENSSL_IS_OPENSSL3 |
| X509 *cert = SSL_get1_peer_certificate(ssl); |
| #else |
| X509 *cert = SSL_get_peer_certificate(ssl); |
| #endif |
| if (cert != nullptr) { |
| print_certificate(result, X509_get_subject_name(cert)); |
| X509_free(cert); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_connection_dns_san_local_certificate.size()) == p_connection_dns_san_local_certificate) { |
| if (txnp_ == nullptr) { |
| *result = pv_empty; |
| return WasmResult::Ok; |
| } |
| TSHttpSsn ssnp = TSHttpTxnSsnGet(txnp_); |
| TSVConn client_conn = TSHttpSsnClientVConnGet(ssnp); |
| TSSslConnection sslobj = TSVConnSslConnectionGet(client_conn); |
| SSL *ssl = reinterpret_cast<SSL *>(sslobj); |
| X509 *cert = SSL_get_certificate(ssl); |
| if (cert != nullptr) { |
| print_san_certificate(result, cert, GEN_DNS); |
| X509_free(cert); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_connection_dns_san_peer_certificate.size()) == p_connection_dns_san_peer_certificate) { |
| if (txnp_ == nullptr) { |
| *result = pv_empty; |
| return WasmResult::Ok; |
| } |
| TSHttpSsn ssnp = TSHttpTxnSsnGet(txnp_); |
| TSVConn client_conn = TSHttpSsnClientVConnGet(ssnp); |
| TSSslConnection sslobj = TSVConnSslConnectionGet(client_conn); |
| SSL *ssl = reinterpret_cast<SSL *>(sslobj); |
| #ifdef OPENSSL_IS_OPENSSL3 |
| X509 *cert = SSL_get1_peer_certificate(ssl); |
| #else |
| X509 *cert = SSL_get_peer_certificate(ssl); |
| #endif |
| if (cert != nullptr) { |
| print_san_certificate(result, cert, GEN_DNS); |
| X509_free(cert); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_connection_uri_san_local_certificate.size()) == p_connection_uri_san_local_certificate) { |
| if (txnp_ == nullptr) { |
| *result = pv_empty; |
| return WasmResult::Ok; |
| } |
| TSHttpSsn ssnp = TSHttpTxnSsnGet(txnp_); |
| TSVConn client_conn = TSHttpSsnClientVConnGet(ssnp); |
| TSSslConnection sslobj = TSVConnSslConnectionGet(client_conn); |
| SSL *ssl = reinterpret_cast<SSL *>(sslobj); |
| X509 *cert = SSL_get_certificate(ssl); |
| if (cert != nullptr) { |
| print_san_certificate(result, cert, GEN_URI); |
| X509_free(cert); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_connection_uri_san_peer_certificate.size()) == p_connection_uri_san_peer_certificate) { |
| if (txnp_ == nullptr) { |
| *result = pv_empty; |
| return WasmResult::Ok; |
| } |
| TSHttpSsn ssnp = TSHttpTxnSsnGet(txnp_); |
| TSVConn client_conn = TSHttpSsnClientVConnGet(ssnp); |
| TSSslConnection sslobj = TSVConnSslConnectionGet(client_conn); |
| SSL *ssl = reinterpret_cast<SSL *>(sslobj); |
| #ifdef OPENSSL_IS_OPENSSL3 |
| X509 *cert = SSL_get1_peer_certificate(ssl); |
| #else |
| X509 *cert = SSL_get_peer_certificate(ssl); |
| #endif |
| if (cert != nullptr) { |
| print_san_certificate(result, cert, GEN_URI); |
| X509_free(cert); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_upstream_address.size()) == p_upstream_address) { |
| if (txnp_ == nullptr) { |
| *result = pv_empty; |
| return WasmResult::Ok; |
| } |
| struct sockaddr const *server_ip = nullptr; |
| server_ip = TSHttpTxnServerAddrGet(txnp_); |
| print_address(server_ip, result); |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_upstream_port.size()) == p_upstream_port) { |
| if (txnp_ == nullptr) { |
| *result = pv_empty; |
| return WasmResult::Ok; |
| } |
| struct sockaddr const *server_ip = nullptr; |
| server_ip = TSHttpTxnClientAddrGet(txnp_); |
| print_port(server_ip, result); |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_upstream_local_address.size()) == p_upstream_local_address) { |
| if (txnp_ == nullptr) { |
| *result = pv_empty; |
| return WasmResult::Ok; |
| } |
| struct sockaddr const *local_ip = nullptr; |
| local_ip = TSHttpTxnOutgoingAddrGet(txnp_); |
| print_address(local_ip, result); |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_upstream_local_port.size()) == p_upstream_local_port) { |
| if (txnp_ == nullptr) { |
| *result = pv_empty; |
| return WasmResult::Ok; |
| } |
| struct sockaddr const *local_ip = nullptr; |
| local_ip = TSHttpTxnOutgoingAddrGet(txnp_); |
| print_port(local_ip, result); |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_upstream_tls_version.size()) == p_upstream_tls_version) { |
| if (txnp_ == nullptr) { |
| *result = pv_empty; |
| return WasmResult::Ok; |
| } |
| const char *ssl_protocol = "-"; |
| TSHttpSsn ssnp = TSHttpTxnSsnGet(txnp_); |
| TSVConn server_conn = TSHttpSsnServerVConnGet(ssnp); |
| |
| if (TSVConnIsSsl(server_conn) != 0) { |
| ssl_protocol = TSVConnSslProtocolGet(server_conn); |
| } |
| |
| result->assign(ssl_protocol); |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_upstream_subject_local_certificate.size()) == p_upstream_subject_local_certificate) { |
| if (txnp_ == nullptr) { |
| *result = pv_empty; |
| return WasmResult::Ok; |
| } |
| TSHttpSsn ssnp = TSHttpTxnSsnGet(txnp_); |
| TSVConn client_conn = TSHttpSsnServerVConnGet(ssnp); |
| TSSslConnection sslobj = TSVConnSslConnectionGet(client_conn); |
| SSL *ssl = reinterpret_cast<SSL *>(sslobj); |
| X509 *cert = SSL_get_certificate(ssl); |
| if (cert != nullptr) { |
| print_certificate(result, X509_get_subject_name(cert)); |
| X509_free(cert); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_upstream_subject_peer_certificate.size()) == p_upstream_subject_peer_certificate) { |
| if (txnp_ == nullptr) { |
| *result = pv_empty; |
| return WasmResult::Ok; |
| } |
| TSHttpSsn ssnp = TSHttpTxnSsnGet(txnp_); |
| TSVConn client_conn = TSHttpSsnServerVConnGet(ssnp); |
| TSSslConnection sslobj = TSVConnSslConnectionGet(client_conn); |
| SSL *ssl = reinterpret_cast<SSL *>(sslobj); |
| #ifdef OPENSSL_IS_OPENSSL3 |
| X509 *cert = SSL_get1_peer_certificate(ssl); |
| #else |
| X509 *cert = SSL_get_peer_certificate(ssl); |
| #endif |
| if (cert != nullptr) { |
| print_certificate(result, X509_get_subject_name(cert)); |
| X509_free(cert); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_upstream_dns_san_local_certificate.size()) == p_upstream_dns_san_local_certificate) { |
| if (txnp_ == nullptr) { |
| *result = pv_empty; |
| return WasmResult::Ok; |
| } |
| TSHttpSsn ssnp = TSHttpTxnSsnGet(txnp_); |
| TSVConn client_conn = TSHttpSsnServerVConnGet(ssnp); |
| TSSslConnection sslobj = TSVConnSslConnectionGet(client_conn); |
| SSL *ssl = reinterpret_cast<SSL *>(sslobj); |
| X509 *cert = SSL_get_certificate(ssl); |
| if (cert != nullptr) { |
| print_san_certificate(result, cert, GEN_DNS); |
| X509_free(cert); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_upstream_dns_san_peer_certificate.size()) == p_upstream_dns_san_peer_certificate) { |
| if (txnp_ == nullptr) { |
| *result = pv_empty; |
| return WasmResult::Ok; |
| } |
| TSHttpSsn ssnp = TSHttpTxnSsnGet(txnp_); |
| TSVConn client_conn = TSHttpSsnServerVConnGet(ssnp); |
| TSSslConnection sslobj = TSVConnSslConnectionGet(client_conn); |
| SSL *ssl = reinterpret_cast<SSL *>(sslobj); |
| #ifdef OPENSSL_IS_OPENSSL3 |
| X509 *cert = SSL_get1_peer_certificate(ssl); |
| #else |
| X509 *cert = SSL_get_peer_certificate(ssl); |
| #endif |
| if (cert != nullptr) { |
| print_san_certificate(result, cert, GEN_DNS); |
| X509_free(cert); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_upstream_uri_san_local_certificate.size()) == p_upstream_uri_san_local_certificate) { |
| if (txnp_ == nullptr) { |
| *result = pv_empty; |
| return WasmResult::Ok; |
| } |
| TSHttpSsn ssnp = TSHttpTxnSsnGet(txnp_); |
| TSVConn client_conn = TSHttpSsnServerVConnGet(ssnp); |
| TSSslConnection sslobj = TSVConnSslConnectionGet(client_conn); |
| SSL *ssl = reinterpret_cast<SSL *>(sslobj); |
| X509 *cert = SSL_get_certificate(ssl); |
| if (cert != nullptr) { |
| print_san_certificate(result, cert, GEN_URI); |
| X509_free(cert); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_upstream_uri_san_peer_certificate.size()) == p_upstream_uri_san_peer_certificate) { |
| if (txnp_ == nullptr) { |
| *result = pv_empty; |
| return WasmResult::Ok; |
| } |
| TSHttpSsn ssnp = TSHttpTxnSsnGet(txnp_); |
| TSVConn client_conn = TSHttpSsnServerVConnGet(ssnp); |
| TSSslConnection sslobj = TSVConnSslConnectionGet(client_conn); |
| SSL *ssl = reinterpret_cast<SSL *>(sslobj); |
| #ifdef OPENSSL_IS_OPENSSL3 |
| X509 *cert = SSL_get1_peer_certificate(ssl); |
| #else |
| X509 *cert = SSL_get_peer_certificate(ssl); |
| #endif |
| if (cert != nullptr) { |
| print_san_certificate(result, cert, GEN_URI); |
| X509_free(cert); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_request_path.size()) == p_request_path) { |
| TSMBuffer bufp = nullptr; |
| TSMLoc hdr_loc = nullptr; |
| TSMLoc url_loc = nullptr; |
| const char *path = nullptr; |
| int path_len = 0; |
| const char *query = nullptr; |
| int query_len = 0; |
| |
| if (TSHttpTxnClientReqGet(txnp_, &bufp, &hdr_loc) == TS_SUCCESS) { |
| if (TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc) == TS_SUCCESS) { |
| path = TSUrlPathGet(bufp, url_loc, &path_len); |
| std::string path_str(path, path_len); |
| |
| query = TSUrlHttpQueryGet(bufp, url_loc, &query_len); |
| std::string query_str(query, query_len); |
| |
| if (query_len > 0) { |
| result->assign("/" + path_str + "?" + query_str); |
| } else { |
| result->assign("/" + path_str); |
| } |
| TSHandleMLocRelease(bufp, hdr_loc, url_loc); |
| } else { |
| *result = pv_empty; |
| } |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_request_url_path.size()) == p_request_url_path) { |
| TSMBuffer bufp = nullptr; |
| TSMLoc hdr_loc = nullptr; |
| TSMLoc url_loc = nullptr; |
| const char *path = nullptr; |
| int path_len = 0; |
| |
| if (TSHttpTxnClientReqGet(txnp_, &bufp, &hdr_loc) == TS_SUCCESS) { |
| if (TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc) == TS_SUCCESS) { |
| path = TSUrlPathGet(bufp, url_loc, &path_len); |
| std::string path_str(path, path_len); |
| result->assign("/" + path_str); |
| TSHandleMLocRelease(bufp, hdr_loc, url_loc); |
| } else { |
| *result = pv_empty; |
| } |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_request_host.size()) == p_request_host) { |
| TSMBuffer bufp = nullptr; |
| TSMLoc hdr_loc = nullptr; |
| TSMLoc url_loc = nullptr; |
| const char *host = nullptr; |
| int host_len = 0; |
| |
| if (TSHttpTxnClientReqGet(txnp_, &bufp, &hdr_loc) == TS_SUCCESS) { |
| if (TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc) == TS_SUCCESS) { |
| host = TSUrlHostGet(bufp, url_loc, &host_len); |
| if (host_len == 0) { |
| const char *key = "Host"; |
| const char *l_key = "host"; |
| int key_len = 4; |
| |
| TSMLoc field_loc = nullptr; |
| |
| field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, key, key_len); |
| if (field_loc != nullptr) { |
| host = TSMimeHdrFieldValueStringGet(bufp, hdr_loc, field_loc, -1, &host_len); |
| TSHandleMLocRelease(bufp, hdr_loc, field_loc); |
| } else { |
| field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, l_key, key_len); |
| if (field_loc != nullptr) { |
| host = TSMimeHdrFieldValueStringGet(bufp, hdr_loc, field_loc, -1, &host_len); |
| TSHandleMLocRelease(bufp, hdr_loc, field_loc); |
| } |
| } |
| } |
| Dbg(dbg_ctl, "[%s] request host value(%d): %.*s", __FUNCTION__, host_len, host_len, host); |
| result->assign(host, host_len); |
| TSHandleMLocRelease(bufp, hdr_loc, url_loc); |
| } else { |
| *result = pv_empty; |
| } |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_request_scheme.size()) == p_request_scheme) { |
| TSMBuffer bufp = nullptr; |
| TSMLoc hdr_loc = nullptr; |
| TSMLoc url_loc = nullptr; |
| const char *scheme = nullptr; |
| int scheme_len = 0; |
| |
| if (TSHttpTxnClientReqGet(txnp_, &bufp, &hdr_loc) == TS_SUCCESS) { |
| if (TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc) == TS_SUCCESS) { |
| scheme = TSUrlSchemeGet(bufp, url_loc, &scheme_len); |
| result->assign(scheme, scheme_len); |
| TSHandleMLocRelease(bufp, hdr_loc, url_loc); |
| } else { |
| *result = pv_empty; |
| } |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_request_method.size()) == p_request_method) { |
| TSMBuffer bufp = nullptr; |
| TSMLoc hdr_loc = nullptr; |
| const char *method = nullptr; |
| int method_len = 0; |
| |
| if (TSHttpTxnClientReqGet(txnp_, &bufp, &hdr_loc) == TS_SUCCESS) { |
| method = TSHttpHdrMethodGet(bufp, hdr_loc, &method_len); |
| result->assign(method, method_len); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_request_query.size()) == p_request_query) { |
| TSMBuffer bufp = nullptr; |
| TSMLoc hdr_loc = nullptr; |
| TSMLoc url_loc = nullptr; |
| const char *query = nullptr; |
| int query_len = 0; |
| |
| if (TSHttpTxnClientReqGet(txnp_, &bufp, &hdr_loc) == TS_SUCCESS) { |
| if (TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc) == TS_SUCCESS) { |
| query = TSUrlHttpQueryGet(bufp, url_loc, &query_len); |
| result->assign(query, query_len); |
| TSHandleMLocRelease(bufp, hdr_loc, url_loc); |
| } else { |
| *result = pv_empty; |
| } |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_request_referer.size()) == p_request_referer) { |
| TSMBuffer bufp = nullptr; |
| TSMLoc hdr_loc = nullptr; |
| if (TSHttpTxnClientReqGet(txnp_, &bufp, &hdr_loc) == TS_SUCCESS) { |
| get_header(bufp, hdr_loc, "Referer", result); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_request_useragent.size()) == p_request_useragent) { |
| TSMBuffer bufp = nullptr; |
| TSMLoc hdr_loc = nullptr; |
| if (TSHttpTxnClientReqGet(txnp_, &bufp, &hdr_loc) == TS_SUCCESS) { |
| get_header(bufp, hdr_loc, "User-Agent", result); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_request_id.size()) == p_request_id) { |
| TSMBuffer bufp = nullptr; |
| TSMLoc hdr_loc = nullptr; |
| if (TSHttpTxnClientReqGet(txnp_, &bufp, &hdr_loc) == TS_SUCCESS) { |
| bool found = get_header(bufp, hdr_loc, "x-request-id", result); |
| if (!found) { |
| uint64_t id = TSHttpTxnIdGet(txnp_); |
| result->assign(std::to_string(id)); |
| } |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } else { |
| uint64_t id = TSHttpTxnIdGet(txnp_); |
| result->assign(std::to_string(id)); |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_request_headers.size()) == p_request_headers) { |
| std::string_view key_sv = path.substr(p_request_headers.size(), path.size() - p_request_headers.size() - 1); |
| |
| TSMBuffer bufp = nullptr; |
| TSMLoc hdr_loc = nullptr; |
| if (TSHttpTxnClientReqGet(txnp_, &bufp, &hdr_loc) == TS_SUCCESS) { |
| get_header(bufp, hdr_loc, key_sv, result); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_request_protocol.size()) == p_request_protocol) { |
| if (TSHttpTxnClientProtocolStackContains(txnp_, "h2") != nullptr) { |
| *result = pv_http2; |
| } else if (TSHttpTxnClientProtocolStackContains(txnp_, "http/1.0") != nullptr) { |
| *result = pv_http10; |
| } else if (TSHttpTxnClientProtocolStackContains(txnp_, "http/1.1") != nullptr) { |
| *result = pv_http11; |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_request_time.size()) == p_request_time) { |
| TSHRTime epoch = 0; |
| if (TS_SUCCESS == TSHttpTxnMilestoneGet(txnp_, TS_MILESTONE_SM_START, &epoch)) { |
| double timestamp = static_cast<double>(epoch) / 1000000000; |
| result->assign(reinterpret_cast<const char *>(×tamp), sizeof(double)); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_request_duration.size()) == p_request_duration) { |
| TSHRTime value = 0; |
| TSHRTime epoch = 0; |
| |
| if (TS_SUCCESS == TSHttpTxnMilestoneGet(txnp_, TS_MILESTONE_SM_START, &epoch)) { |
| if (TS_SUCCESS == TSHttpTxnMilestoneGet(txnp_, TS_MILESTONE_SM_FINISH, &value)) { |
| double duration = static_cast<double>((value - epoch)) / 1000000000; |
| result->assign(reinterpret_cast<const char *>(&duration), sizeof(double)); |
| return WasmResult::Ok; |
| } |
| } |
| *result = pv_empty; |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_request_size.size()) == p_request_size) { |
| int64_t bytes = TSHttpTxnClientReqBodyBytesGet(txnp_); |
| result->assign(reinterpret_cast<const char *>(&bytes), sizeof(int64_t)); |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_request_total_size.size()) == p_request_total_size) { |
| int h_bytes = TSHttpTxnClientReqHdrBytesGet(txnp_); |
| int64_t b_bytes = TSHttpTxnClientReqBodyBytesGet(txnp_); |
| int64_t total = h_bytes + b_bytes; |
| result->assign(reinterpret_cast<const char *>(&total), sizeof(int64_t)); |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_response_code.size()) == p_response_code) { |
| TSMBuffer bufp = nullptr; |
| TSMLoc hdr_loc = nullptr; |
| int status = 0; |
| |
| if (TSHttpTxnServerRespGet(txnp_, &bufp, &hdr_loc) == TS_SUCCESS) { |
| status = TSHttpHdrStatusGet(bufp, hdr_loc); |
| result->assign(reinterpret_cast<const char *>(&status), sizeof(int)); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_response_code_details.size()) == p_response_code_details) { |
| TSMBuffer bufp = nullptr; |
| TSMLoc hdr_loc = nullptr; |
| const char *reason = nullptr; |
| int reason_len = 0; |
| |
| if (TSHttpTxnServerRespGet(txnp_, &bufp, &hdr_loc) == TS_SUCCESS) { |
| reason = TSHttpHdrReasonGet(bufp, hdr_loc, &reason_len); |
| result->assign(reason, reason_len); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_response_headers.size()) == p_response_headers) { |
| std::string_view key_sv = path.substr(p_response_headers.size(), path.size() - p_response_headers.size() - 1); |
| TSMBuffer bufp = nullptr; |
| TSMLoc hdr_loc = nullptr; |
| if (TSHttpTxnServerRespGet(txnp_, &bufp, &hdr_loc) == TS_SUCCESS) { |
| get_header(bufp, hdr_loc, key_sv, result); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } else { |
| *result = pv_empty; |
| } |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_response_size.size()) == p_response_size) { |
| int64_t bytes = TSHttpTxnServerRespBodyBytesGet(txnp_); |
| result->assign(reinterpret_cast<const char *>(&bytes), sizeof(int64_t)); |
| return WasmResult::Ok; |
| } else if (path.substr(0, p_response_total_size.size()) == p_response_total_size) { |
| int h_bytes = TSHttpTxnServerRespHdrBytesGet(txnp_); |
| int64_t b_bytes = TSHttpTxnServerRespBodyBytesGet(txnp_); |
| int64_t total = h_bytes + b_bytes; |
| result->assign(reinterpret_cast<const char *>(&total), sizeof(int64_t)); |
| return WasmResult::Ok; |
| } else { |
| *result = pv_empty; |
| Dbg(dbg_ctl, "[%s] looking for unknown property: empty string", __FUNCTION__); |
| return WasmResult::Ok; |
| } |
| } |
| |
| WasmResult |
| Context::setProperty(std::string_view key, std::string_view serialized_value) |
| { |
| if (key.substr(0, p_request_url_path.size()) == p_request_url_path) { |
| TSMBuffer bufp = nullptr; |
| TSMLoc hdr_loc = nullptr; |
| TSMLoc url_loc = nullptr; |
| std::string_view result; |
| |
| if (serialized_value.substr(0, 1) == "/") { |
| result = serialized_value.substr(1); |
| } else { |
| result = serialized_value; |
| } |
| |
| if (TSHttpTxnClientReqGet(txnp_, &bufp, &hdr_loc) == TS_SUCCESS) { |
| if (TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc) == TS_SUCCESS) { |
| TSUrlPathSet(bufp, url_loc, result.data(), result.size()); |
| TSHandleMLocRelease(bufp, hdr_loc, url_loc); |
| } |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } |
| return WasmResult::Ok; |
| } else if (key.substr(0, p_request_host.size()) == p_request_host) { |
| TSMBuffer bufp = nullptr; |
| TSMLoc hdr_loc = nullptr; |
| TSMLoc url_loc = nullptr; |
| |
| if (TSHttpTxnClientReqGet(txnp_, &bufp, &hdr_loc) == TS_SUCCESS) { |
| if (TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc) == TS_SUCCESS) { |
| TSUrlHostSet(bufp, url_loc, serialized_value.data(), serialized_value.size()); |
| TSHandleMLocRelease(bufp, hdr_loc, url_loc); |
| } |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } |
| return WasmResult::Ok; |
| } else if (key.substr(0, p_request_scheme.size()) == p_request_scheme) { |
| TSMBuffer bufp = nullptr; |
| TSMLoc hdr_loc = nullptr; |
| TSMLoc url_loc = nullptr; |
| |
| if (TSHttpTxnClientReqGet(txnp_, &bufp, &hdr_loc) == TS_SUCCESS) { |
| if (TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc) == TS_SUCCESS) { |
| TSUrlSchemeSet(bufp, url_loc, serialized_value.data(), serialized_value.size()); |
| TSHandleMLocRelease(bufp, hdr_loc, url_loc); |
| } |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } |
| return WasmResult::Ok; |
| } else if (key.substr(0, p_request_method.size()) == p_request_method) { |
| TSMBuffer bufp = nullptr; |
| TSMLoc hdr_loc = nullptr; |
| |
| if (TSHttpTxnClientReqGet(txnp_, &bufp, &hdr_loc) == TS_SUCCESS) { |
| TSHttpHdrMethodSet(bufp, hdr_loc, serialized_value.data(), serialized_value.size()); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } |
| return WasmResult::Ok; |
| } else if (key.substr(0, p_request_query.size()) == p_request_query) { |
| TSMBuffer bufp = nullptr; |
| TSMLoc hdr_loc = nullptr; |
| TSMLoc url_loc = nullptr; |
| |
| if (TSHttpTxnClientReqGet(txnp_, &bufp, &hdr_loc) == TS_SUCCESS) { |
| if (TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc) == TS_SUCCESS) { |
| TSUrlHttpQuerySet(bufp, url_loc, serialized_value.data(), serialized_value.size()); |
| TSHandleMLocRelease(bufp, hdr_loc, url_loc); |
| } |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } |
| return WasmResult::Ok; |
| } else if (key.substr(0, p_request_headers.size()) == p_request_headers) { |
| std::string_view key_sv = key.substr(p_request_headers.size(), key.size() - p_request_headers.size() - 1); |
| |
| TSMBuffer bufp = nullptr; |
| TSMLoc hdr_loc = nullptr; |
| |
| if (TSHttpTxnClientReqGet(txnp_, &bufp, &hdr_loc) == TS_SUCCESS) { |
| set_header(bufp, hdr_loc, key_sv, serialized_value); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } |
| return WasmResult::Ok; |
| } else if (key.substr(0, p_response_code.size()) == p_response_code) { |
| TSMBuffer bufp = nullptr; |
| TSMLoc hdr_loc = nullptr; |
| |
| if (TSHttpTxnServerRespGet(txnp_, &bufp, &hdr_loc) == TS_SUCCESS) { |
| int64_t *status = reinterpret_cast<int64_t *>(const_cast<char *>(serialized_value.data())); |
| TSHttpHdrStatusSet(bufp, hdr_loc, static_cast<TSHttpStatus>(*status), txnp_, WASM_DEBUG_TAG); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } |
| return WasmResult::Ok; |
| } else if (key.substr(0, p_response_code_details.size()) == p_response_code_details) { |
| TSMBuffer bufp = nullptr; |
| TSMLoc hdr_loc = nullptr; |
| |
| if (TSHttpTxnServerRespGet(txnp_, &bufp, &hdr_loc) == TS_SUCCESS) { |
| TSHttpHdrReasonSet(bufp, hdr_loc, serialized_value.data(), serialized_value.size()); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } |
| return WasmResult::Ok; |
| } else if (key.substr(0, p_response_headers.size()) == p_response_headers) { |
| std::string_view key_sv = key.substr(p_response_headers.size(), key.size() - p_response_headers.size() - 1); |
| |
| TSMBuffer bufp = nullptr; |
| TSMLoc hdr_loc = nullptr; |
| |
| if (TSHttpTxnServerRespGet(txnp_, &bufp, &hdr_loc) == TS_SUCCESS) { |
| set_header(bufp, hdr_loc, key_sv, serialized_value); |
| TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); |
| } |
| return WasmResult::Ok; |
| } |
| return WasmResult::Ok; |
| } |
| |
| WasmResult |
| Context::continueStream(WasmStreamType /* stream_type */) |
| { |
| if (reenable_txn_) { |
| TSError("[wasm][%s] transaction already reenabled", __FUNCTION__); |
| return WasmResult::Ok; |
| } |
| |
| if (txnp_ == nullptr) { |
| TSError("[wasm][%s] Can't continue stream without a transaction", __FUNCTION__); |
| return WasmResult::InternalFailure; |
| } else { |
| Dbg(dbg_ctl, "[%s] continuing txn for context %d", __FUNCTION__, id()); |
| reenable_txn_ = true; |
| TSHttpTxnReenable(txnp_, TS_EVENT_HTTP_CONTINUE); |
| return WasmResult::Ok; |
| } |
| } |
| |
| WasmResult |
| Context::closeStream(WasmStreamType /* stream_type */) |
| { |
| if (reenable_txn_) { |
| TSError("[wasm][%s] transaction already reenabled", __FUNCTION__); |
| return WasmResult::Ok; |
| } |
| |
| if (txnp_ == nullptr) { |
| TSError("[wasm][%s] Can't continue stream without a transaction", __FUNCTION__); |
| return WasmResult::InternalFailure; |
| } else { |
| Dbg(dbg_ctl, "[%s] continue txn for context %d with error", __FUNCTION__, id()); |
| reenable_txn_ = true; |
| TSHttpTxnReenable(txnp_, TS_EVENT_HTTP_ERROR); |
| return WasmResult::Ok; |
| } |
| } |
| |
| // send pre-made response |
| WasmResult |
| Context::sendLocalResponse(uint32_t response_code, std::string_view body_text, Pairs additional_headers, |
| GrpcStatusCode /* grpc_status */, std::string_view details) |
| { |
| if (txnp_ == nullptr) { |
| TSError("[wasm][%s] Can't send local response without a transaction", __FUNCTION__); |
| return WasmResult::InternalFailure; |
| } else { |
| TSHttpTxnStatusSet(txnp_, static_cast<TSHttpStatus>(response_code), WASM_DEBUG_TAG); |
| |
| if (body_text.size() > 0) { |
| TSHttpTxnErrorBodySet(txnp_, TSstrndup(body_text.data(), body_text.size()), body_text.size(), |
| nullptr); // Defaults to text/html |
| } |
| |
| local_reply_headers_ = additional_headers; |
| local_reply_details_ = details; |
| local_reply_ = true; |
| } |
| return WasmResult::Ok; |
| } |
| |
| WasmResult |
| Context::getSharedData(std::string_view key, std::pair<std::string, uint32_t> *data) |
| { |
| return proxy_wasm::getGlobalSharedData().get(wasm_->vm_id(), key, data); |
| } |
| |
| // Header/Trailer/Metadata Maps |
| WasmResult |
| Context::addHeaderMapValue(WasmHeaderMapType type, std::string_view key, std::string_view value) |
| { |
| auto map = getHeaderMap(type); |
| if (map.bufp == nullptr) { |
| TSError("[wasm][%s] Invalid type", __FUNCTION__); |
| return WasmResult::BadArgument; |
| } |
| auto *field_loc = TSMimeHdrFieldFind(map.bufp, map.hdr_loc, key.data(), static_cast<int>(key.size())); |
| if (TS_NULL_MLOC == field_loc) { |
| if (TS_SUCCESS != TSMimeHdrFieldCreateNamed(map.bufp, map.hdr_loc, key.data(), static_cast<int>(key.size()), &field_loc)) { |
| TSError("[wasm][%s] Cannot create named field", __FUNCTION__); |
| return WasmResult::InternalFailure; |
| } |
| } |
| if (TS_SUCCESS == |
| TSMimeHdrFieldValueStringSet(map.bufp, map.hdr_loc, field_loc, -1, value.data(), static_cast<int>(value.size()))) { |
| TSMimeHdrFieldAppend(map.bufp, map.hdr_loc, field_loc); |
| TSHandleMLocRelease(map.bufp, map.hdr_loc, field_loc); |
| return WasmResult::Ok; |
| } else { |
| TSError("[wasm][%s] Cannot set field value", __FUNCTION__); |
| TSHandleMLocRelease(map.bufp, map.hdr_loc, field_loc); |
| return WasmResult::InternalFailure; |
| } |
| } |
| |
| WasmResult |
| Context::getHeaderMapValue(WasmHeaderMapType type, std::string_view key, std::string_view *result) |
| { |
| auto map = getHeaderMap(type); |
| if (map.bufp == nullptr) { |
| TSError("[wasm][%s] Invalid type", __FUNCTION__); |
| return WasmResult::BadArgument; |
| } |
| if (map.bufp != nullptr) { |
| auto *loc = TSMimeHdrFieldFind(map.bufp, map.hdr_loc, key.data(), static_cast<int>(key.size())); |
| if (TS_NULL_MLOC != loc) { |
| int vlen = 0; |
| // TODO: add support for dups |
| auto *v = TSMimeHdrFieldValueStringGet(map.bufp, map.hdr_loc, loc, 0, &vlen); |
| std::string_view temp(v, vlen); |
| *result = temp; |
| TSHandleMLocRelease(map.bufp, map.hdr_loc, loc); |
| return WasmResult::Ok; |
| } else { |
| *result = ""; |
| return WasmResult::Ok; |
| } |
| } |
| return WasmResult::NotFound; |
| } |
| |
| WasmResult |
| Context::getHeaderMapPairs(WasmHeaderMapType type, Pairs *result) |
| { |
| auto map = getHeaderMap(type); |
| if (map.bufp == nullptr) { |
| TSError("[wasm][%s] Invalid type", __FUNCTION__); |
| return WasmResult::BadArgument; |
| } |
| int num = map.size(); |
| |
| result->reserve(num); |
| for (int i = 0; i < num; i++) { |
| auto *loc = TSMimeHdrFieldGet(map.bufp, map.hdr_loc, i); |
| int nlen = 0; |
| auto *n = TSMimeHdrFieldNameGet(map.bufp, map.hdr_loc, loc, &nlen); |
| int vlen = 0; |
| // TODO: add support for dups. |
| auto *v = TSMimeHdrFieldValueStringGet(map.bufp, map.hdr_loc, loc, 0, &vlen); |
| result->push_back( |
| std::make_pair(std::string_view(n, static_cast<size_t>(nlen)), std::string_view(v, static_cast<size_t>(vlen)))); |
| TSHandleMLocRelease(map.bufp, map.hdr_loc, loc); |
| } |
| return WasmResult::Ok; |
| } |
| |
| WasmResult |
| Context::setHeaderMapPairs(WasmHeaderMapType type, const Pairs &pairs) |
| { |
| auto map = getHeaderMap(type); |
| if (map.bufp == nullptr) { |
| TSError("[wasm][%s] Invalid type", __FUNCTION__); |
| return WasmResult::BadArgument; |
| } |
| |
| for (const auto &p : pairs) { |
| std::string key(p.first); |
| std::string value(p.second); |
| |
| auto *loc = TSMimeHdrFieldFind(map.bufp, map.hdr_loc, key.data(), static_cast<int>(key.size())); |
| if (loc != TS_NULL_MLOC) { |
| int first = 1; |
| while (loc != TS_NULL_MLOC) { |
| auto *tmp = TSMimeHdrFieldNextDup(map.bufp, map.hdr_loc, loc); |
| if (first != 0) { |
| first = 0; |
| TSMimeHdrFieldValueStringSet(map.bufp, map.hdr_loc, loc, -1, value.data(), static_cast<int>(value.size())); |
| } else { |
| TSMimeHdrFieldDestroy(map.bufp, map.hdr_loc, loc); |
| } |
| TSHandleMLocRelease(map.bufp, map.hdr_loc, loc); |
| loc = tmp; |
| } |
| } else if (TSMimeHdrFieldCreateNamed(map.bufp, map.hdr_loc, key.data(), static_cast<int>(key.size()), &loc) != TS_SUCCESS) { |
| TSError("[wasm][%s] TSMimeHdrFieldCreateNamed error", __FUNCTION__); |
| return WasmResult::InternalFailure; |
| } else { |
| TSMimeHdrFieldValueStringSet(map.bufp, map.hdr_loc, loc, -1, value.data(), static_cast<int>(value.size())); |
| TSMimeHdrFieldAppend(map.bufp, map.hdr_loc, loc); |
| } |
| |
| if (loc != TS_NULL_MLOC) { |
| TSHandleMLocRelease(map.bufp, map.hdr_loc, loc); |
| } |
| } |
| |
| return WasmResult::Ok; |
| } |
| |
| WasmResult |
| Context::removeHeaderMapValue(WasmHeaderMapType type, std::string_view key) |
| { |
| auto map = getHeaderMap(type); |
| if (map.bufp == nullptr) { |
| TSError("[wasm][%s] Invalid type", __FUNCTION__); |
| return WasmResult::BadArgument; |
| } |
| if (map.bufp != nullptr) { |
| auto *loc = TSMimeHdrFieldFind(map.bufp, map.hdr_loc, key.data(), static_cast<int>(key.size())); |
| while (loc != TS_NULL_MLOC) { |
| auto *tmp = TSMimeHdrFieldNextDup(map.bufp, map.hdr_loc, loc); |
| TSMimeHdrFieldDestroy(map.bufp, map.hdr_loc, loc); |
| TSHandleMLocRelease(map.bufp, map.hdr_loc, loc); |
| loc = tmp; |
| } |
| } |
| |
| return WasmResult::Ok; |
| } |
| |
| WasmResult |
| Context::replaceHeaderMapValue(WasmHeaderMapType type, std::string_view key, std::string_view value) |
| { |
| auto map = getHeaderMap(type); |
| if (map.bufp == nullptr) { |
| TSError("[wasm][%s] Invalid type", __FUNCTION__); |
| return WasmResult::BadArgument; |
| } |
| if (map.bufp != nullptr) { |
| auto *loc = TSMimeHdrFieldFind(map.bufp, map.hdr_loc, key.data(), static_cast<int>(key.size())); |
| |
| if (loc != TS_NULL_MLOC) { |
| int first = 1; |
| while (loc != TS_NULL_MLOC) { |
| auto *tmp = TSMimeHdrFieldNextDup(map.bufp, map.hdr_loc, loc); |
| if (first != 0) { |
| first = 0; |
| TSMimeHdrFieldValueStringSet(map.bufp, map.hdr_loc, loc, -1, value.data(), static_cast<int>(value.size())); |
| } else { |
| TSMimeHdrFieldDestroy(map.bufp, map.hdr_loc, loc); |
| } |
| TSHandleMLocRelease(map.bufp, map.hdr_loc, loc); |
| loc = tmp; |
| } |
| } |
| } |
| return WasmResult::Ok; |
| } |
| |
| WasmResult |
| Context::getHeaderMapSize(WasmHeaderMapType type, uint32_t *result) |
| { |
| auto map = getHeaderMap(type); |
| if (map.bufp == nullptr) { |
| TSError("[wasm][%s] Invalid type", __FUNCTION__); |
| return WasmResult::BadArgument; |
| } |
| *result = TSMimeHdrLengthGet(map.bufp, map.hdr_loc); |
| return WasmResult::Ok; |
| } |
| |
| HeaderMap |
| Context::getHeaderMap(WasmHeaderMapType type) |
| { |
| HeaderMap map; |
| switch (type) { |
| case WasmHeaderMapType::RequestHeaders: |
| if (txnp_ == nullptr) { |
| return {}; |
| } |
| if (TSHttpTxnClientReqGet(txnp_, &map.bufp, &map.hdr_loc) == TS_SUCCESS) { |
| return map; |
| } |
| return {}; |
| case WasmHeaderMapType::RequestTrailers: |
| return {}; |
| case WasmHeaderMapType::ResponseHeaders: |
| if (txnp_ == nullptr) { |
| return {}; |
| } |
| if (TSHttpTxnServerRespGet(txnp_, &map.bufp, &map.hdr_loc) == TS_SUCCESS) { |
| return map; |
| } |
| return {}; |
| case WasmHeaderMapType::ResponseTrailers: |
| return {}; |
| case WasmHeaderMapType::HttpCallResponseHeaders: |
| if (cr_hdr_buf_ == nullptr || cr_hdr_loc_ == nullptr) { |
| return {}; |
| } |
| map.bufp = cr_hdr_buf_; |
| map.hdr_loc = cr_hdr_loc_; |
| return map; |
| default: |
| case WasmHeaderMapType::GrpcReceiveTrailingMetadata: |
| case WasmHeaderMapType::GrpcReceiveInitialMetadata: |
| case WasmHeaderMapType::HttpCallResponseTrailers: |
| return {}; |
| } |
| } |
| |
| } // namespace ats_wasm |