LCOV - code coverage report
Current view: top level - http2 - MyTrafficHttp2Server.cpp (source / functions) Coverage Total Hit
Test: final-coverage.info Lines: 90.9 % 164 149
Test Date: 2025-11-03 01:58:56 Functions: 90.9 % 11 10

            Line data    Source code
       1              : /*
       2              :  ___________________________________________
       3              : |    _     ___                        _     |
       4              : |   | |   |__ \                      | |    |
       5              : |   | |__    ) |__ _  __ _  ___ _ __ | |_   |
       6              : |   | '_ \  / // _` |/ _` |/ _ \ '_ \| __|  |  HTTP/2 AGENT FOR MOCK TESTING
       7              : |   | | | |/ /| (_| | (_| |  __/ | | | |_   |  Version 0.0.z
       8              : |   |_| |_|____\__,_|\__, |\___|_| |_|\__|  |  https://github.com/testillano/h2agent
       9              : |                     __/ |                 |
      10              : |                    |___/                  |
      11              : |___________________________________________|
      12              : 
      13              : Licensed under the MIT License <http://opensource.org/licenses/MIT>.
      14              : SPDX-License-Identifier: MIT
      15              : Copyright (c) 2021 Eduardo Ramos
      16              : 
      17              : Permission is hereby  granted, free of charge, to any  person obtaining a copy
      18              : of this software and associated  documentation files (the "Software"), to deal
      19              : in the Software  without restriction, including without  limitation the rights
      20              : to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
      21              : copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
      22              : furnished to do so, subject to the following conditions:
      23              : 
      24              : The above copyright notice and this permission notice shall be included in all
      25              : copies or substantial portions of the Software.
      26              : 
      27              : THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
      28              : IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
      29              : FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
      30              : AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
      31              : LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      32              : OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
      33              : SOFTWARE.
      34              : */
      35              : 
      36              : #include <boost/optional.hpp>
      37              : #include <sstream>
      38              : #include <map>
      39              : #include <errno.h>
      40              : 
      41              : 
      42              : #include <ert/tracing/Logger.hpp>
      43              : #include <ert/http2comm/Http.hpp>
      44              : #include <ert/http2comm/Http2Headers.hpp>
      45              : 
      46              : #include <MyTrafficHttp2Server.hpp>
      47              : 
      48              : #include <AdminData.hpp>
      49              : #include <MockServerData.hpp>
      50              : #include <Configuration.hpp>
      51              : #include <GlobalVariable.hpp>
      52              : #include <FileManager.hpp>
      53              : #include <SocketManager.hpp>
      54              : #include <functions.hpp>
      55              : 
      56              : namespace h2agent
      57              : {
      58              : namespace http2
      59              : {
      60              : 
      61              : 
      62           49 : MyTrafficHttp2Server::MyTrafficHttp2Server(const std::string &name, size_t workerThreads, size_t maxWorkerThreads, boost::asio::io_context *timersIoContext, int maxQueueDispatcherSize):
      63              :     ert::http2comm::Http2Server(name, workerThreads, maxWorkerThreads, timersIoContext, maxQueueDispatcherSize),
      64           49 :     admin_data_(nullptr) {
      65              : 
      66           49 :     server_data_ = true;
      67           49 :     server_data_key_history_ = true;
      68           49 :     purge_execution_ = true;
      69           49 : }
      70              : 
      71           30 : void MyTrafficHttp2Server::enableMyMetrics(ert::metrics::Metrics *metrics, const std::string &source) {
      72              : 
      73           30 :     metrics_ = metrics;
      74              : 
      75           30 :     if (metrics_) {
      76           90 :         ert::metrics::labels_t familyLabels = {{"source", (source.empty() ? name_:source)}}; // same way that http2comm library
      77              : 
      78          120 :         ert::metrics::counter_family_t& cf = metrics->addCounterFamily("h2agent_traffic_server_provisioned_requests_counter", "Requests provisioned counter in h2agent_traffic_server", familyLabels);
      79              : 
      80           90 :         provisioned_requests_successful_counter_ = &(cf.Add({{"result", "successful"}}));
      81           90 :         provisioned_requests_failed_counter_ = &(cf.Add({{"result", "failed"}}));
      82              : 
      83          120 :         ert::metrics::counter_family_t& cf2 = metrics->addCounterFamily("h2agent_traffic_server_purged_contexts_counter", "Contexts purged counter in h2agent_traffic_server", familyLabels);
      84              : 
      85           90 :         purged_contexts_successful_counter_ = &(cf2.Add({{"result", "successful"}}));
      86           90 :         purged_contexts_failed_counter_ = &(cf2.Add({{"result", "failed"}}));
      87           30 :     }
      88          180 : }
      89              : 
      90           11 : bool MyTrafficHttp2Server::checkMethodIsAllowed(
      91              :     const nghttp2::asio_http2::server::request& req,
      92              :     std::vector<std::string>& allowedMethods)
      93              : {
      94              :     // NO RESTRICTIONS FOR SIMULATED NODE
      95           66 :     allowedMethods = {"POST", "GET", "PUT", "DELETE", "HEAD"};
      96           11 :     return (req.method() == "POST" || req.method() == "GET" || req.method() == "PUT" || req.method() == "DELETE" || req.method() == "HEAD");
      97           33 : }
      98              : 
      99           11 : bool MyTrafficHttp2Server::checkMethodIsImplemented(
     100              :     const nghttp2::asio_http2::server::request& req)
     101              : {
     102              :     // NO RESTRICTIONS FOR SIMULATED NODE
     103           11 :     return (req.method() == "POST" || req.method() == "GET" || req.method() == "PUT" || req.method() == "DELETE" || req.method() == "HEAD");
     104              : }
     105              : 
     106              : 
     107           11 : bool MyTrafficHttp2Server::checkHeaders(const nghttp2::asio_http2::server::request&
     108              :                                         req)
     109              : {
     110           11 :     return true;
     111              :     /*
     112              :         auto ctype = req.header().find("content-type");
     113              :         auto ctype_end = std::end(req.header());
     114              : 
     115              :         return ((ctype != ctype_end) ? (ctype->second.value == "application/json") :
     116              :                 false);
     117              :     */
     118              : }
     119              : 
     120            6 : std::string MyTrafficHttp2Server::dataConfigurationAsJsonString() const {
     121            6 :     nlohmann::json result;
     122              : 
     123            6 :     result["storeEvents"] = server_data_;
     124            6 :     result["storeEventsKeyHistory"] = server_data_key_history_;
     125            6 :     result["purgeExecution"] = purge_execution_;
     126              : 
     127           12 :     return result.dump();
     128            6 : }
     129              : 
     130            2 : std::string MyTrafficHttp2Server::configurationAsJsonString() const {
     131            2 :     nlohmann::json result;
     132              : 
     133            2 :     result["receiveRequestBody"] = receive_request_body_.load();
     134            2 :     result["preReserveRequestBody"] = pre_reserve_request_body_.load();
     135              : 
     136            4 :     return result.dump();
     137            2 : }
     138              : 
     139            0 : bool MyTrafficHttp2Server::receiveDataLen(const nghttp2::asio_http2::server::request& req) {
     140            0 :     LOGDEBUG(ert::tracing::Logger::debug("receiveRequestBody()",  ERT_FILE_LOCATION));
     141              : 
     142              :     // TODO: we could analyze req to get the provision and find out if request body is actually needed.
     143              :     // To cache the analysis, we should use complete URI as map key (data/len could be received in
     144              :     // chunks and that's why data/len reception sequence id is not valid and it is not provided by
     145              :     // http2comm library through this virtual method).
     146              : 
     147            0 :     return receive_request_body_.load();
     148              : }
     149              : 
     150           11 : bool MyTrafficHttp2Server::preReserveRequestBody() {
     151           11 :     return pre_reserve_request_body_.load();
     152              : }
     153              : 
     154           11 : void MyTrafficHttp2Server::receive(const std::uint64_t &receptionId,
     155              :                                    const nghttp2::asio_http2::server::request& req,
     156              :                                    const std::string &requestBody,
     157              :                                    const std::chrono::microseconds &receptionTimestampUs,
     158              :                                    unsigned int& statusCode, nghttp2::asio_http2::header_map& headers,
     159              :                                    std::string& responseBody, unsigned int &responseDelayMs)
     160              : {
     161           11 :     LOGDEBUG(ert::tracing::Logger::debug("receive()",  ERT_FILE_LOCATION));
     162              : 
     163              :     // see uri_ref struct (https://nghttp2.org/documentation/asio_http2.h.html#asio-http2-h)
     164           11 :     std::string method = req.method();
     165              :     //std::string uriRawPath = req.uri().raw_path; // percent-encoded
     166           11 :     std::string uriPath = req.uri().path; // decoded
     167           11 :     std::string uriQuery = req.uri().raw_query; // parameter values may be percent-encoded
     168              :     //std::string reqUriFragment = req.uri().fragment; // https://stackoverflow.com/a/65198345/2576671
     169              : 
     170              :     // Move request body to internal encoded body data:
     171           11 :     h2agent::model::DataPart requestBodyDataPart(std::move(requestBody));
     172              : 
     173              :     // Busy threads:
     174           11 :     int currentBusyThreads = getQueueDispatcherBusyThreads();
     175           11 :     if (currentBusyThreads > 0) { // 0 when queue dispatcher is not used
     176            8 :         int maxBusyThreads = max_busy_threads_.load();
     177            8 :         if (currentBusyThreads > maxBusyThreads) {
     178            5 :             maxBusyThreads = currentBusyThreads;
     179            5 :             max_busy_threads_.store(maxBusyThreads);
     180              :         }
     181            8 :         LOGINFORMATIONAL(
     182              :         if (receptionId % 1000 == 0) {
     183              :         std::string msg = ert::tracing::Logger::asString("QueueDispatcher [workers/size/max-size]: %d/%d/%d | Busy workers [current/maximum reached]: %d/%d", getQueueDispatcherThreads(), getQueueDispatcherSize(), getQueueDispatcherMaxSize(), currentBusyThreads, maxBusyThreads);
     184              :             ert::tracing::Logger::informational(msg,  ERT_FILE_LOCATION);
     185              :         }
     186              :         );
     187              :     }
     188              : 
     189           11 :     LOGDEBUG(
     190              :         std::stringstream ss;
     191              :         // Original URI:
     192              :         std::string originalUri = uriPath;
     193              :     if (!uriQuery.empty()) {
     194              :     originalUri += "?";
     195              :     originalUri += uriQuery;
     196              : }
     197              : ss << "TRAFFIC REQUEST RECEIVED"
     198              :    << " | Reception id (general unique server sequence): " << receptionId
     199              :    << " | Method: " << method
     200              :    << " | Headers: " << ert::http2comm::headersAsString(req.header())
     201              :    << " | Uri: " << req.uri().scheme << "://" << req.uri().host << originalUri
     202              :    << " | Query parameters: " << ((getAdminData()->getServerMatchingData().getUriPathQueryParametersFilter() == h2agent::model::AdminServerMatchingData::Ignore) ? "ignored":"not ignored")
     203              :    << " | Body (as ascii string, dots for non-printable): " << requestBodyDataPart.asAsciiString();
     204              :    ert::tracing::Logger::debug(ss.str(), ERT_FILE_LOCATION);
     205              : );
     206              : 
     207              :     // Normalized URI: original URI with query parameters normalized (ordered) / Classification URI: may ignore, sort or pass by query parameters
     208           11 :     std::string normalizedUri = uriPath;
     209           11 :     std::string classificationUri = uriPath;
     210              : 
     211              :     // Query parameters transformation:
     212           11 :     std::map<std::string, std::string> qmap; // query parameters map
     213           11 :     if (!uriQuery.empty()) {
     214            9 :         char separator = ((getAdminData()->getServerMatchingData().getUriPathQueryParametersSeparator() == h2agent::model::AdminServerMatchingData::Ampersand) ? '&':';');
     215            9 :         std::string uriQueryNormalized;
     216            9 :         std::string *ptr_uriQueryNormalized = &uriQueryNormalized;
     217            9 :         qmap = h2agent::model::extractQueryParameters(uriQuery, ptr_uriQueryNormalized, separator); // needed even for 'Ignore' QParam filter type
     218              : 
     219            9 :         normalizedUri += "?";
     220            9 :         normalizedUri += uriQueryNormalized;
     221              : 
     222            9 :         h2agent::model::AdminServerMatchingData::UriPathQueryParametersFilterType uriPathQueryParametersFilterType = getAdminData()->getServerMatchingData().getUriPathQueryParametersFilter();
     223            9 :         switch (uriPathQueryParametersFilterType) {
     224            1 :         case h2agent::model::AdminServerMatchingData::PassBy:
     225            1 :             classificationUri += "?";
     226            1 :             classificationUri += uriQuery;
     227            1 :             break;
     228            7 :         case h2agent::model::AdminServerMatchingData::Sort:
     229            7 :             classificationUri += "?";
     230            7 :             classificationUri += uriQueryNormalized;
     231            7 :             break;
     232            1 :         case h2agent::model::AdminServerMatchingData::Ignore:
     233            1 :             break;
     234              :         }
     235            9 :     }
     236              : 
     237           11 :     LOGDEBUG(
     238              :         std::stringstream ss;
     239              :         ss << "Normalized Uri (server data event keys): " << req.uri().scheme << "://" << req.uri().host << normalizedUri;
     240              :         ert::tracing::Logger::debug(ss.str(), ERT_FILE_LOCATION);
     241              :     );
     242              : 
     243              : // Admin provision & matching configuration:
     244           11 :     const h2agent::model::AdminServerProvisionData & provisionData = getAdminData()->getServerProvisionData();
     245           11 :     const h2agent::model::AdminServerMatchingData & matchingData = getAdminData()->getServerMatchingData();
     246              : 
     247              : // Find mock context:
     248           22 :     std::string inState{};
     249           22 :     h2agent::model::DataKey normalizedKey(method, normalizedUri);
     250              : 
     251           11 :     /*bool requestFound = */getMockServerData()->findLastRegisteredRequestState(normalizedKey, inState); // if not found, inState will be 'initial'
     252              : 
     253              : // Matching algorithm:
     254           11 :     h2agent::model::AdminServerMatchingData::AlgorithmType algorithmType = matchingData.getAlgorithm();
     255           11 :     std::shared_ptr<h2agent::model::AdminServerProvision> provision(nullptr);
     256              : 
     257           11 :     LOGDEBUG(
     258              :         std::stringstream ss;
     259              :     if (algorithmType != h2agent::model::AdminServerMatchingData::FullMatchingRegexReplace) {
     260              :     ss << "Classification Uri: " << req.uri().scheme << "://" << req.uri().host << classificationUri;
     261              :         ert::tracing::Logger::debug(ss.str(), ERT_FILE_LOCATION);
     262              :     }
     263              :     );
     264              : 
     265           11 :     switch (algorithmType) {
     266            9 :     case h2agent::model::AdminServerMatchingData::FullMatching:
     267            9 :         LOGDEBUG(
     268              :             std::string msg = ert::tracing::Logger::asString("Searching 'FullMatching' provision for method '%s', classification uri '%s' and state '%s'", method.c_str(), classificationUri.c_str(), inState.c_str());
     269              :             ert::tracing::Logger::debug(msg, ERT_FILE_LOCATION);
     270              :         );
     271            9 :         provision = provisionData.find(inState, method, classificationUri);
     272            9 :         break;
     273              : 
     274            1 :     case h2agent::model::AdminServerMatchingData::FullMatchingRegexReplace:
     275              :         // In this case, our classification URI is pending to be transformed:
     276            1 :         classificationUri = std::regex_replace (classificationUri, matchingData.getRgx(), matchingData.getFmt());
     277            1 :         LOGDEBUG(
     278              :             std::string msg = ert::tracing::Logger::asString("Classification Uri (after regex-replace transformation): %s", classificationUri.c_str());
     279              :             ert::tracing::Logger::debug(msg, ERT_FILE_LOCATION);
     280              :             msg = ert::tracing::Logger::asString("Searching 'FullMatchingRegexReplace' provision for method '%s', classification uri '%s' and state '%s'", method.c_str(), classificationUri.c_str(), inState.c_str());
     281              :             ert::tracing::Logger::debug(msg, ERT_FILE_LOCATION);
     282              :         );
     283            1 :         provision = provisionData.find(inState, method, classificationUri);
     284            1 :         break;
     285            1 :     case h2agent::model::AdminServerMatchingData::RegexMatching:
     286            1 :         LOGDEBUG(
     287              :             std::string msg = ert::tracing::Logger::asString("Searching 'RegexMatching' provision for method '%s', classification uri '%s' and state '%s'", method.c_str(), classificationUri.c_str(), inState.c_str());
     288              :             ert::tracing::Logger::debug(msg, ERT_FILE_LOCATION);
     289              :         );
     290              : 
     291              :         // as provision key is built combining inState, method and uri fields, a regular expression could also be provided for inState
     292              :         //  (method is strictly checked). TODO could we avoid this rare and unpredictable usage ?
     293            1 :         provision = provisionData.findRegexMatching(inState, method, classificationUri);
     294            1 :         break;
     295              :     }
     296              : 
     297              :     // Fall back to possible default provision (empty URI):
     298           11 :     if (!provision) {
     299            6 :         LOGDEBUG(
     300              :             std::string msg = ert::tracing::Logger::asString("No provision found for classification URI. Trying with default fallback provision for '%s'", method.c_str());
     301              :             ert::tracing::Logger::debug(msg, ERT_FILE_LOCATION);
     302              :         );
     303              : 
     304           12 :         provision = provisionData.find(inState, method, "");
     305              :     }
     306              : 
     307           11 :     if (provision) {
     308              : 
     309            5 :         LOGDEBUG(ert::tracing::Logger::debug("Provision successfully indentified !", ERT_FILE_LOCATION));
     310            5 :         provision->employ();
     311              : 
     312            5 :         std::string outState;
     313            5 :         std::string outStateMethod;
     314            5 :         std::string outStateUri;
     315              : 
     316              :         // Process provision
     317            5 :         provision->transform(normalizedUri, uriPath, qmap, requestBodyDataPart, req.header(), receptionId,
     318              :                              statusCode, headers, responseBody, responseDelayMs, outState, outStateMethod, outStateUri);
     319              : 
     320              :         // Special out-states:
     321            5 :         if (purge_execution_ && outState == "purge") {
     322            1 :             bool somethingDeleted = false;
     323            2 :             bool success = getMockServerData()->clear(somethingDeleted, h2agent::model::EventKey(normalizedKey, ""));
     324            1 :             LOGDEBUG(
     325              :                 std::string msg = ert::tracing::Logger::asString("Requested purge in out-state. Removal %s", success ? "successful":"failed");
     326              :                 ert::tracing::Logger::debug(msg, ERT_FILE_LOCATION);
     327              :             );
     328              :             // metrics
     329            1 :             if(metrics_) {
     330            1 :                 if (success) purged_contexts_successful_counter_->Increment();
     331            0 :                 else purged_contexts_failed_counter_->Increment();
     332              :             }
     333              :         }
     334              :         else {
     335            4 :             bool hasVirtualMethod = !outStateMethod.empty();
     336              : 
     337              :             // Store event context information
     338            4 :             if (server_data_) {
     339            4 :                 normalizedKey.setProvisionUri(provision->getRequestUri()); // additional context
     340           16 :                 getMockServerData()->loadEvent(normalizedKey, inState, (hasVirtualMethod ? provision->getOutState():outState), receptionTimestampUs, statusCode, req.header(), headers, requestBodyDataPart, responseBody, receptionId, responseDelayMs, server_data_key_history_ /* history enabled */);
     341              : 
     342              :                 // Virtual storage:
     343            4 :                 if (hasVirtualMethod) {
     344            2 :                     LOGWARNING(
     345              :                         if (outStateMethod == method && outStateUri.empty()) ert::tracing::Logger::warning(ert::tracing::Logger::asString("Redundant 'outState' foreign method with current provision one: '%s'", method.c_str()), ERT_FILE_LOCATION);
     346              :                     );
     347            2 :                     if (outStateUri.empty()) {
     348            0 :                         outStateUri = normalizedUri; // by default
     349              :                     }
     350              : 
     351            2 :                     h2agent::model::DataKey foreignKey(outStateMethod /* foreign method */, outStateUri /* foreign uri */);
     352            2 :                     foreignKey.setProvisionUri(provision->getRequestUri()); // additional context
     353            2 :                     getMockServerData()->loadEvent(foreignKey, inState, outState, receptionTimestampUs, statusCode, req.header(), headers, requestBodyDataPart, responseBody, receptionId, responseDelayMs, server_data_key_history_ /* history enabled */, method /* virtual method origin*/, normalizedUri /* virtual uri origin */);
     354            2 :                 }
     355              :             }
     356              :         }
     357              : 
     358              :         // metrics
     359            5 :         if(metrics_) {
     360            3 :             provisioned_requests_successful_counter_->Increment();
     361              :         }
     362            5 :     }
     363              :     else {
     364            6 :         LOGDEBUG(
     365              :             std::string msg = ert::tracing::Logger::asString("Default fallback provision not found: returning status code 501 (Not Implemented).", method.c_str());
     366              :             ert::tracing::Logger::debug(msg, ERT_FILE_LOCATION);
     367              :         );
     368              : 
     369            6 :         statusCode = ert::http2comm::ResponseCode::NOT_IMPLEMENTED; // 501
     370              :         // Store even if not provision was identified (helps to troubleshoot design problems in test configuration):
     371            6 :         if (server_data_) {
     372           54 :             getMockServerData()->loadEvent(normalizedKey, ""/* empty inState, which will be omitted in server data register */, ""/*outState (same as before)*/, receptionTimestampUs, statusCode, req.header(), headers, requestBodyDataPart, responseBody, receptionId, responseDelayMs, true /* history enabled ALWAYS FOR UNKNOWN EVENTS */);
     373              :         }
     374              :         // metrics
     375            6 :         if(metrics_) {
     376            5 :             provisioned_requests_failed_counter_->Increment();
     377              :         }
     378              :     }
     379              : 
     380              : 
     381           11 :     LOGDEBUG(
     382              :         std::stringstream ss;
     383              :         ss << "RESPONSE TO SEND| StatusCode: " << statusCode << " | Headers: " << ert::http2comm::headersAsString(headers);
     384              :     if (!responseBody.empty()) {
     385              :     std::string output;
     386              :     h2agent::model::asAsciiString(responseBody, output);
     387              :         ss << " | Body (as ascii string, dots for non-printable): " << output;
     388              :     }
     389              :     ert::tracing::Logger::debug(ss.str(), ERT_FILE_LOCATION);
     390              :     );
     391           11 : }
     392              : 
     393           11 : std::chrono::microseconds MyTrafficHttp2Server::responseDelayTimer(const std::uint64_t &receptionId) {
     394              : 
     395           11 :     bool exists{};
     396           11 :     long long micro_count{};
     397              : 
     398           11 :     if (global_variable_ptr_) {
     399              : 
     400           13 :         static const std::string varPrefix = "ResponseDelayTimerUS.ReceptionId.";
     401           11 :         std::string var = varPrefix + std::to_string(receptionId);
     402           11 :         std::string val = global_variable_ptr_->get(var, exists);
     403           11 :         if (exists) {
     404              :             try {
     405            0 :                 micro_count = std::stoll(val);
     406            0 :                 LOGDEBUG(ert::tracing::Logger::debug(ert::tracing::Logger::asString("Variable value processed (%s = %s)", var.c_str(), val.c_str()), ERT_FILE_LOCATION));
     407            0 :             } catch (const std::invalid_argument& e) {
     408            0 :                 LOGWARNING(ert::tracing::Logger::warning(ert::tracing::Logger::asString("Variable value is not a number (%s = %s)", var.c_str(), val.c_str()), ERT_FILE_LOCATION));
     409            0 :                 return std::chrono::microseconds::zero();
     410            0 :             } catch (const std::out_of_range& e) {
     411            0 :                 LOGWARNING(ert::tracing::Logger::warning(ert::tracing::Logger::asString("Variable value invalid range (%s = %s)", var.c_str(), val.c_str()), ERT_FILE_LOCATION));
     412            0 :                 return std::chrono::microseconds::zero();
     413            0 :             }
     414              :         }
     415           11 :     }
     416              :     else {
     417            0 :         LOGWARNING(ert::tracing::Logger::warning("You may need to set global variable map to server instance: myTrafficHttp2Server->setGlobalVariable(myGlobalVariable);", ERT_FILE_LOCATION));
     418              :     }
     419              : 
     420           11 :     return std::chrono::microseconds(micro_count);
     421              : }
     422              : 
     423              : }
     424              : }
        

Generated by: LCOV version 2.0-1