_ZN3uWS12TemplatedAppILb0EEC2ENS_20SocketContextOptionsE:
  217|  1.65k|    TemplatedApp(SocketContextOptions options = {}) {
  218|  1.65k|        httpContext = HttpContext<SSL>::create(Loop::get(), options);
  219|  1.65k|    }
_ZNK3uWS20SocketContextOptionscv27us_socket_context_options_tEv:
   71|  1.65k|        operator struct us_socket_context_options_t() const {
   72|  1.65k|            struct us_socket_context_options_t socket_context_options;
   73|  1.65k|            memcpy(&socket_context_options, this, sizeof(SocketContextOptions));
   74|  1.65k|            return socket_context_options;
   75|  1.65k|        }
_ZN3uWS12TemplatedAppILb0EED2Ev:
  177|  3.31k|    ~TemplatedApp() {
  178|       |        /* Let's just put everything here */
  179|  3.31k|        if (httpContext) {
  ------------------
  |  Branch (179:13): [True: 1.65k, False: 1.65k]
  ------------------
  180|  1.65k|            httpContext->free();
  181|       |
  182|       |            /* Free all our webSocketContexts in a type less way */
  183|  1.65k|            for (auto &webSocketContextDeleter : webSocketContextDeleters) {
  ------------------
  |  Branch (183:48): [True: 0, False: 1.65k]
  ------------------
  184|      0|                webSocketContextDeleter();
  185|      0|            }
  186|  1.65k|        }
  187|       |
  188|       |        /* Delete TopicTree */
  189|  3.31k|        if (topicTree) {
  ------------------
  |  Branch (189:13): [True: 0, False: 3.31k]
  ------------------
  190|      0|            delete topicTree;
  191|       |
  192|       |            /* And unregister loop callbacks */
  193|       |            /* We must unregister any loop post handler here */
  194|      0|            Loop::get()->removePostHandler(topicTree);
  195|      0|            Loop::get()->removePreHandler(topicTree);
  196|      0|        }
  197|  3.31k|    }
_ZN3uWS12TemplatedAppILb0EE3getENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEON5ofats13any_invocableIFvPNS_12HttpResponseILb0EEEPNS_11HttpRequestEEEE:
  457|  1.65k|    TemplatedApp &&get(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
  458|  1.65k|        if (httpContext) {
  ------------------
  |  Branch (458:13): [True: 1.65k, False: 0]
  ------------------
  459|  1.65k|            httpContext->onHttp("GET", pattern, std::move(handler));
  460|  1.65k|        }
  461|  1.65k|        return std::move(*this);
  462|  1.65k|    }
_ZN3uWS12TemplatedAppILb0EE6listenEiON5ofats13any_invocableIFvP18us_listen_socket_tEEE:
  547|  1.65k|    TemplatedApp &&listen(int port, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {
  548|  1.65k|        handler(httpContext ? httpContext->listen(nullptr, port, 0) : nullptr);
  ------------------
  |  Branch (548:17): [True: 1.65k, False: 0]
  ------------------
  549|  1.65k|        return std::move(*this);
  550|  1.65k|    }
_ZN3uWS12TemplatedAppILb0EEC2EOS1_:
  202|  1.65k|    TemplatedApp(TemplatedApp &&other) {
  203|       |        /* Move HttpContext */
  204|  1.65k|        httpContext = other.httpContext;
  205|  1.65k|        other.httpContext = nullptr;
  206|       |
  207|       |        /* Move webSocketContextDeleters */
  208|  1.65k|        webSocketContextDeleters = std::move(other.webSocketContextDeleters);
  209|       |
  210|  1.65k|        webSocketContexts = std::move(other.webSocketContexts);
  211|       |
  212|       |        /* Move TopicTree */
  213|  1.65k|        topicTree = other.topicTree;
  214|  1.65k|        other.topicTree = nullptr;
  215|  1.65k|    }
_ZN3uWS12TemplatedAppILb0EE3runEv:
  570|  1.65k|    TemplatedApp &&run() {
  571|  1.65k|        uWS::run();
  572|  1.65k|        return std::move(*this);
  573|  1.65k|    }

_ZN3uWS11AsyncSocketILb0EE4corkEv:
  133|   146k|    void cork() {
  134|       |        /* Extra check for invalid corking of others */
  135|   146k|        if (getLoopData()->corkOffset && getLoopData()->corkedSocket != this) {
  ------------------
  |  Branch (135:13): [True: 0, False: 146k]
  |  Branch (135:42): [True: 0, False: 0]
  ------------------
  136|      0|            std::cerr << "Error: Cork buffer must not be acquired without checking canCork!" << std::endl;
  137|      0|            std::terminate();
  138|      0|        }
  139|       |
  140|       |        /* What if another socket is corked? */
  141|   146k|        getLoopData()->corkedSocket = this;
  142|   146k|    }
_ZN3uWS11AsyncSocketILb0EE11getLoopDataEv:
   85|   764k|    LoopData *getLoopData() {
   86|   764k|        return (LoopData *) us_loop_ext(us_socket_context_loop(SSL, us_socket_context(SSL, (us_socket_t *) this)));
   87|   764k|    }
_ZN3uWS11AsyncSocketILb0EE6uncorkEPKcib:
  332|   146k|    std::pair<int, bool> uncork(const char *src = nullptr, int length = 0, bool optionally = false) {
  333|   146k|        LoopData *loopData = getLoopData();
  334|       |
  335|   146k|        if (loopData->corkedSocket == this) {
  ------------------
  |  Branch (335:13): [True: 146k, False: 0]
  ------------------
  336|   146k|            loopData->corkedSocket = nullptr;
  337|       |
  338|   146k|            if (loopData->corkOffset) {
  ------------------
  |  Branch (338:17): [True: 12.6k, False: 133k]
  ------------------
  339|       |                /* Corked data is already accounted for via its write call */
  340|  12.6k|                auto [written, failed] = write(loopData->corkBuffer, (int) loopData->corkOffset, false, length);
  341|  12.6k|                loopData->corkOffset = 0;
  342|       |
  343|  12.6k|                if (failed) {
  ------------------
  |  Branch (343:21): [True: 11.0k, False: 1.52k]
  ------------------
  344|       |                    /* We do not need to care for buffering here, write does that */
  345|  11.0k|                    return {0, true};
  346|  11.0k|                }
  347|  12.6k|            }
  348|       |
  349|       |            /* We should only return with new writes, not things written to cork already */
  350|   134k|            return write(src, length, optionally, 0);
  351|   146k|        } else {
  352|       |            /* We are not even corked! */
  353|      0|            return {0, false};
  354|      0|        }
  355|   146k|    }
_ZN3uWS11AsyncSocketILb0EE5writeEPKcibi:
  241|   354k|    std::pair<int, bool> write(const char *src, int length, bool optionally = false, int nextLength = 0) {
  242|       |        /* Fake success if closed, simple fix to allow uncork of closed socket to succeed */
  243|   354k|        if (us_socket_is_closed(SSL, (us_socket_t *) this)) {
  ------------------
  |  Branch (243:13): [True: 92.9k, False: 261k]
  ------------------
  244|  92.9k|            return {length, false};
  245|  92.9k|        }
  246|       |
  247|   261k|        LoopData *loopData = getLoopData();
  248|   261k|        AsyncSocketData<SSL> *asyncSocketData = getAsyncSocketData();
  249|       |
  250|       |        /* We are limited if we have a per-socket buffer */
  251|   261k|        if (asyncSocketData->buffer.length()) {
  ------------------
  |  Branch (251:13): [True: 40.2k, False: 221k]
  ------------------
  252|       |            /* Write off as much as we can */
  253|  40.2k|            int written = us_socket_write(SSL, (us_socket_t *) this, asyncSocketData->buffer.data(), (int) asyncSocketData->buffer.length(), /*nextLength != 0 | */length);
  254|       |
  255|       |            /* On failure return, otherwise continue down the function */
  256|  40.2k|            if ((unsigned int) written < asyncSocketData->buffer.length()) {
  ------------------
  |  Branch (256:17): [True: 36.0k, False: 4.12k]
  ------------------
  257|       |
  258|       |                /* Update buffering (todo: we can do better here if we keep track of what happens to this guy later on) */
  259|  36.0k|                asyncSocketData->buffer.erase((unsigned int) written);
  260|       |
  261|  36.0k|                if (optionally) {
  ------------------
  |  Branch (261:21): [True: 7.98k, False: 28.1k]
  ------------------
  262|       |                    /* Thankfully we can exit early here */
  263|  7.98k|                    return {0, true};
  264|  28.1k|                } else {
  265|       |                    /* This path is horrible and points towards erroneous usage */
  266|  28.1k|                    asyncSocketData->buffer.append(src, (unsigned int) length);
  267|       |
  268|  28.1k|                    return {length, true};
  269|  28.1k|                }
  270|  36.0k|            }
  271|       |
  272|       |            /* At this point we simply have no buffer and can continue as normal */
  273|  4.12k|            asyncSocketData->buffer.clear();
  274|  4.12k|        }
  275|       |
  276|   225k|        if (length) {
  ------------------
  |  Branch (276:13): [True: 193k, False: 31.4k]
  ------------------
  277|   193k|            if (loopData->corkedSocket == this) {
  ------------------
  |  Branch (277:17): [True: 181k, False: 12.6k]
  ------------------
  278|       |                /* We are corked */
  279|   181k|                if (LoopData::CORK_BUFFER_SIZE - loopData->corkOffset >= (unsigned int) length) {
  ------------------
  |  Branch (279:21): [True: 181k, False: 0]
  ------------------
  280|       |                    /* If the entire chunk fits in cork buffer */
  281|   181k|                    memcpy(loopData->corkBuffer + loopData->corkOffset, src, (unsigned int) length);
  282|   181k|                    loopData->corkOffset += (unsigned int) length;
  283|       |                    /* Fall through to default return */
  284|   181k|                } else {
  285|       |                    /* Strategy differences between SSL and non-SSL regarding syscall minimizing */
  286|      0|                    if constexpr (SSL) {
  ------------------
  |  Branch (286:35): [Folded - Ignored]
  ------------------
  287|       |                        /* Cork up as much as we can */
  288|      0|                        unsigned int stripped = LoopData::CORK_BUFFER_SIZE - loopData->corkOffset;
  289|      0|                        memcpy(loopData->corkBuffer + loopData->corkOffset, src, stripped);
  290|      0|                        loopData->corkOffset = LoopData::CORK_BUFFER_SIZE;
  291|       |
  292|      0|                        auto [written, failed] = uncork(src + stripped, length - (int) stripped, optionally);
  293|      0|                        return {written + (int) stripped, failed};
  294|      0|                    }
  295|       |
  296|       |                    /* For non-SSL we take the penalty of two syscalls */
  297|      0|                    return uncork(src, length, optionally);
  298|      0|                }
  299|   181k|            } else {
  300|       |                /* We are not corked */
  301|  12.6k|                int written = us_socket_write(SSL, (us_socket_t *) this, src, length, nextLength != 0);
  302|       |
  303|       |                /* Did we fail? */
  304|  12.6k|                if (written < length) {
  ------------------
  |  Branch (304:21): [True: 11.0k, False: 1.52k]
  ------------------
  305|       |                    /* If the write was optional then just bail out */
  306|  11.0k|                    if (optionally) {
  ------------------
  |  Branch (306:25): [True: 0, False: 11.0k]
  ------------------
  307|      0|                        return {written, true};
  308|      0|                    }
  309|       |
  310|       |                    /* Fall back to worst possible case (should be very rare for HTTP) */
  311|       |                    /* At least we can reserve room for next chunk if we know it up front */
  312|  11.0k|                    if (nextLength) {
  ------------------
  |  Branch (312:25): [True: 0, False: 11.0k]
  ------------------
  313|      0|                        asyncSocketData->buffer.reserve(asyncSocketData->buffer.length() + (size_t) (length - written + nextLength));
  314|      0|                    }
  315|       |
  316|       |                    /* Buffer this chunk */
  317|  11.0k|                    asyncSocketData->buffer.append(src + written, (size_t) (length - written));
  318|       |
  319|       |                    /* Return the failure */
  320|  11.0k|                    return {length, true};
  321|  11.0k|                }
  322|       |                /* Fall through to default return */
  323|  12.6k|            }
  324|   193k|        }
  325|       |
  326|       |        /* Default fall through return */
  327|   214k|        return {length, false};
  328|   225k|    }
_ZN3uWS11AsyncSocketILb0EE7timeoutEj:
   95|  47.7k|    void timeout(unsigned int seconds) {
   96|  47.7k|        us_socket_timeout(SSL, (us_socket_t *) this, seconds);
   97|  47.7k|    }
_ZN3uWS11AsyncSocketILb0EE17getBufferedAmountEv:
  198|  6.18k|    unsigned int getBufferedAmount() {
  199|       |        /* We return the actual amount of bytes in backbuffer, including pendingRemoval */
  200|  6.18k|        return (unsigned int) getAsyncSocketData()->buffer.totalLength();
  201|  6.18k|    }
_ZN3uWS11AsyncSocketILb0EE8shutdownEv:
  100|  2.07k|    void shutdown() {
  101|  2.07k|        us_socket_shutdown(SSL, (us_socket_t *) this);
  102|  2.07k|    }
_ZN3uWS11AsyncSocketILb0EE5closeEv:
  117|  29.9k|    us_socket_t *close() {
  118|  29.9k|        return us_socket_close(SSL, (us_socket_t *) this, 0, nullptr);
  119|  29.9k|    }
_ZN3uWS11AsyncSocketILb0EE18getAsyncSocketDataEv:
   90|   413k|    AsyncSocketData<SSL> *getAsyncSocketData() {
   91|   413k|        return (AsyncSocketData<SSL> *) us_socket_ext(SSL, (us_socket_t *) this);
   92|   413k|    }
_ZN3uWS11AsyncSocketILb0EE8isCorkedEv:
  150|  26.1k|    bool isCorked() {
  151|  26.1k|        return getLoopData()->corkedSocket == this;
  152|  26.1k|    }
_ZN3uWS11AsyncSocketILb0EE7canCorkEv:
  155|  13.0k|    bool canCork() {
  156|  13.0k|        return getLoopData()->corkedSocket == nullptr;
  157|  13.0k|    }
_ZN3uWS11AsyncSocketILb0EE12corkedSocketEv:
  145|  13.0k|    void *corkedSocket() {
  146|  13.0k|        return getLoopData()->corkedSocket;
  147|  13.0k|    }

_ZN3uWS15AsyncSocketDataILb0EEC2Ev:
   82|  1.01M|    AsyncSocketData() = default;
_ZN3uWS12BackPressureC2Ev:
   32|  1.01M|    BackPressure() = default;
_ZN3uWS12BackPressure6lengthEv:
   44|   341k|    size_t length() {
   45|   341k|        return buffer.length() - pendingRemoval;
   46|   341k|    }
_ZN3uWS12BackPressure4dataEv:
   57|  40.2k|    const char *data() {
   58|  40.2k|        return buffer.data() + pendingRemoval;
   59|  40.2k|    }
_ZN3uWS12BackPressure5eraseEj:
   36|  36.0k|    void erase(unsigned int length) {
   37|  36.0k|        pendingRemoval += length;
   38|       |        /* Always erase a minimum of 1/32th the current backpressure */
   39|  36.0k|        if (pendingRemoval > (buffer.length() >> 5)) {
  ------------------
  |  Branch (39:13): [True: 22.1k, False: 13.9k]
  ------------------
   40|  22.1k|            buffer.erase(0, pendingRemoval);
   41|  22.1k|            pendingRemoval = 0;
   42|  22.1k|        }
   43|  36.0k|    }
_ZN3uWS12BackPressure6appendEPKcm:
   33|  39.1k|    void append(const char *data, size_t length) {
   34|  39.1k|        buffer.append(data, length);
   35|  39.1k|    }
_ZN3uWS12BackPressure5clearEv:
   47|  4.12k|    void clear() {
   48|  4.12k|        pendingRemoval = 0;
   49|  4.12k|        buffer.clear();
   50|  4.12k|    }
_ZN3uWS12BackPressure11totalLengthEv:
   64|  6.18k|    size_t totalLength() {
   65|  6.18k|        return buffer.length();
   66|  6.18k|    }

_ZN3uWS11BloomFilter5resetEv:
   75|  30.6k|    void reset() {
   76|  30.6k|        filter.reset();
   77|  30.6k|    }
_ZN3uWS11BloomFilter3addENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
   64|  40.3k|    void add(std::string_view key) {
   65|  40.3k|        if (key.length() >= 2) {
  ------------------
  |  Branch (65:13): [True: 36.7k, False: 3.69k]
  ------------------
   66|  36.7k|            ScrambleArea s = getFeatures(key);
   67|  36.7k|            s.val = perfectHash(s.val);
   68|  36.7k|            filter[s.p[0]] = 1;
   69|  36.7k|            filter[s.p[1]] = 1;
   70|  36.7k|            filter[s.p[2]] = 1;
   71|  36.7k|            filter[s.p[3]] = 1;
   72|  36.7k|        }
   73|  40.3k|    }
_ZN3uWS11BloomFilter11getFeaturesENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
   41|   171k|    ScrambleArea getFeatures(std::string_view key) {
   42|   171k|        ScrambleArea s;
   43|   171k|        s.p[0] = reinterpret_cast<const unsigned char&>(key[0]);
   44|   171k|        s.p[1] = reinterpret_cast<const unsigned char&>(key[key.length() - 1]);
   45|   171k|        s.p[2] = reinterpret_cast<const unsigned char&>(key[key.length() - 2]);
   46|   171k|        s.p[3] = reinterpret_cast<const unsigned char&>(key[key.length() >> 1]);
   47|   171k|        return s;
   48|   171k|    }
_ZN3uWS11BloomFilter11perfectHashEj:
   32|   171k|    static inline uint32_t perfectHash(uint32_t features) {
   33|   171k|        return features *= 1843993368;
   34|   171k|    }
_ZN3uWS11BloomFilter9mightHaveENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
   51|   134k|    bool mightHave(std::string_view key) {
   52|   134k|        if (key.length() < 2) {
  ------------------
  |  Branch (52:13): [True: 0, False: 134k]
  ------------------
   53|      0|            return true;
   54|      0|        }
   55|       |    
   56|   134k|        ScrambleArea s = getFeatures(key);
   57|   134k|        s.val = perfectHash(s.val);
   58|   134k|        return filter[s.p[0]] &&
  ------------------
  |  Branch (58:16): [True: 38.2k, False: 96.6k]
  ------------------
   59|   134k|        filter[s.p[1]] &&
  ------------------
  |  Branch (59:9): [True: 36.7k, False: 1.48k]
  ------------------
   60|   134k|        filter[s.p[2]] &&
  ------------------
  |  Branch (60:9): [True: 32.1k, False: 4.61k]
  ------------------
   61|   134k|        filter[s.p[3]];
  ------------------
  |  Branch (61:9): [True: 31.6k, False: 452]
  ------------------
   62|   134k|    }

_ZN3uWS11HttpContextILb0EE6createEPNS_4LoopE27us_socket_context_options_t:
  390|  1.65k|    static HttpContext *create(Loop *loop, us_socket_context_options_t options = {}) {
  391|  1.65k|        HttpContext *httpContext;
  392|       |
  393|  1.65k|        httpContext = (HttpContext *) us_create_socket_context(SSL, (us_loop_t *) loop, sizeof(HttpContextData<SSL>), options);
  394|       |
  395|  1.65k|        if (!httpContext) {
  ------------------
  |  Branch (395:13): [True: 0, False: 1.65k]
  ------------------
  396|      0|            return nullptr;
  397|      0|        }
  398|       |
  399|       |        /* Init socket context data */
  400|  1.65k|        new ((HttpContextData<SSL> *) us_socket_context_ext(SSL, (us_socket_context_t *) httpContext)) HttpContextData<SSL>();
  401|  1.65k|        return httpContext->init();
  402|  1.65k|    }
_ZN3uWS11HttpContextILb0EE4initEv:
   66|  1.65k|    HttpContext<SSL> *init() {
   67|       |        /* Handle socket connections */
   68|  1.65k|        us_socket_context_on_open(SSL, getSocketContext(), [](us_socket_t *s, int /*is_client*/, char */*ip*/, int /*ip_length*/) {
   69|       |            /* Any connected socket should timeout until it has a request */
   70|  1.65k|            us_socket_timeout(SSL, s, HTTP_IDLE_TIMEOUT_S);
   71|       |
   72|       |            /* Init socket ext */
   73|  1.65k|            new (us_socket_ext(SSL, s)) HttpResponseData<SSL>;
   74|       |
   75|       |            /* Call filter */
   76|  1.65k|            HttpContextData<SSL> *httpContextData = getSocketContextDataS(s);
   77|  1.65k|            for (auto &f : httpContextData->filterHandlers) {
   78|  1.65k|                f((HttpResponse<SSL> *) s, 1);
   79|  1.65k|            }
   80|       |
   81|  1.65k|            return s;
   82|  1.65k|        });
   83|       |
   84|       |        /* Handle socket disconnections */
   85|  1.65k|        us_socket_context_on_close(SSL, getSocketContext(), [](us_socket_t *s, int /*code*/, void */*reason*/) {
   86|       |            /* Get socket ext */
   87|  1.65k|            HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) us_socket_ext(SSL, s);
   88|       |
   89|       |            /* Call filter */
   90|  1.65k|            HttpContextData<SSL> *httpContextData = getSocketContextDataS(s);
   91|  1.65k|            for (auto &f : httpContextData->filterHandlers) {
   92|  1.65k|                f((HttpResponse<SSL> *) s, -1);
   93|  1.65k|            }
   94|       |
   95|       |            /* Signal broken HTTP request only if we have a pending request */
   96|  1.65k|            if (httpResponseData->onAborted) {
   97|  1.65k|                httpResponseData->onAborted();
   98|  1.65k|            }
   99|       |
  100|       |            /* Destruct socket ext */
  101|  1.65k|            httpResponseData->~HttpResponseData<SSL>();
  102|       |
  103|  1.65k|            return s;
  104|  1.65k|        });
  105|       |
  106|       |        /* Handle HTTP data streams */
  107|  1.65k|        us_socket_context_on_data(SSL, getSocketContext(), [](us_socket_t *s, char *data, int length) {
  108|       |
  109|       |            // total overhead is about 210k down to 180k
  110|       |            // ~210k req/sec is the original perf with write in data
  111|       |            // ~200k req/sec is with cork and formatting
  112|       |            // ~190k req/sec is with http parsing
  113|       |            // ~180k - 190k req/sec is with varying routing
  114|       |
  115|  1.65k|            HttpContextData<SSL> *httpContextData = getSocketContextDataS(s);
  116|       |
  117|       |            /* Do not accept any data while in shutdown state */
  118|  1.65k|            if (us_socket_is_shut_down(SSL, (us_socket_t *) s)) {
  119|  1.65k|                return s;
  120|  1.65k|            }
  121|       |
  122|  1.65k|            HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) us_socket_ext(SSL, s);
  123|       |
  124|       |            /* Cork this socket */
  125|  1.65k|            ((AsyncSocket<SSL> *) s)->cork();
  126|       |
  127|       |            /* Mark that we are inside the parser now */
  128|  1.65k|            httpContextData->isParsingHttp = true;
  129|       |
  130|       |            // clients need to know the cursor after http parse, not servers!
  131|       |            // how far did we read then? we need to know to continue with websocket parsing data? or?
  132|       |
  133|  1.65k|            void *proxyParser = nullptr;
  134|       |#ifdef UWS_WITH_PROXY
  135|       |            proxyParser = &httpResponseData->proxyParser;
  136|       |#endif
  137|       |
  138|       |            /* The return value is entirely up to us to interpret. The HttpParser only care for whether the returned value is DIFFERENT or not from passed user */
  139|  1.65k|            auto [err, returnedSocket] = httpResponseData->consumePostPadded(data, (unsigned int) length, s, proxyParser, [httpContextData](void *s, HttpRequest *httpRequest) -> void * {
  140|       |                /* For every request we reset the timeout and hang until user makes action */
  141|       |                /* Warning: if we are in shutdown state, resetting the timer is a security issue! */
  142|  1.65k|                us_socket_timeout(SSL, (us_socket_t *) s, 0);
  143|       |
  144|       |                /* Reset httpResponse */
  145|  1.65k|                HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) us_socket_ext(SSL, (us_socket_t *) s);
  146|  1.65k|                httpResponseData->offset = 0;
  147|       |
  148|       |                /* Are we not ready for another request yet? Terminate the connection. */
  149|  1.65k|                if (httpResponseData->state & HttpResponseData<SSL>::HTTP_RESPONSE_PENDING) {
  150|  1.65k|                    us_socket_close(SSL, (us_socket_t *) s, 0, nullptr);
  151|  1.65k|                    return nullptr;
  152|  1.65k|                }
  153|       |
  154|       |                /* Mark pending request and emit it */
  155|  1.65k|                httpResponseData->state = HttpResponseData<SSL>::HTTP_RESPONSE_PENDING;
  156|       |
  157|       |                /* Mark this response as connectionClose if ancient or connection: close */
  158|  1.65k|                if (httpRequest->isAncient() || httpRequest->getHeader("connection").length() == 5) {
  159|  1.65k|                    httpResponseData->state |= HttpResponseData<SSL>::HTTP_CONNECTION_CLOSE;
  160|  1.65k|                }
  161|       |
  162|       |                /* Select the router based on SNI (only possible for SSL) */
  163|  1.65k|                auto *selectedRouter = &httpContextData->router;
  164|  1.65k|                if constexpr (SSL) {
  165|  1.65k|                    void *domainRouter = us_socket_server_name_userdata(SSL, (struct us_socket_t *) s);
  166|  1.65k|                    if (domainRouter) {
  167|  1.65k|                        selectedRouter = (decltype(selectedRouter)) domainRouter;
  168|  1.65k|                    }
  169|  1.65k|                }
  170|       |
  171|       |                /* Route the method and URL */
  172|  1.65k|                selectedRouter->getUserData() = {(HttpResponse<SSL> *) s, httpRequest};
  173|  1.65k|                if (!selectedRouter->route(httpRequest->getCaseSensitiveMethod(), httpRequest->getUrl())) {
  174|       |                    /* We have to force close this socket as we have no handler for it */
  175|  1.65k|                    us_socket_close(SSL, (us_socket_t *) s, 0, nullptr);
  176|  1.65k|                    return nullptr;
  177|  1.65k|                }
  178|       |
  179|       |                /* First of all we need to check if this socket was deleted due to upgrade */
  180|  1.65k|                if (httpContextData->upgradedWebSocket) {
  181|       |                    /* We differ between closed and upgraded below */
  182|  1.65k|                    return nullptr;
  183|  1.65k|                }
  184|       |
  185|       |                /* Was the socket closed? */
  186|  1.65k|                if (us_socket_is_closed(SSL, (struct us_socket_t *) s)) {
  187|  1.65k|                    return nullptr;
  188|  1.65k|                }
  189|       |
  190|       |                /* We absolutely have to terminate parsing if shutdown */
  191|  1.65k|                if (us_socket_is_shut_down(SSL, (us_socket_t *) s)) {
  192|  1.65k|                    return nullptr;
  193|  1.65k|                }
  194|       |
  195|       |                /* Returning from a request handler without responding or attaching an onAborted handler is ill-use */
  196|  1.65k|                if (!((HttpResponse<SSL> *) s)->hasResponded() && !httpResponseData->onAborted) {
  197|       |                    /* Throw exception here? */
  198|  1.65k|                    std::cerr << "Error: Returning from a request handler without responding or attaching an abort handler is forbidden!" << std::endl;
  199|  1.65k|                    std::terminate();
  200|  1.65k|                }
  201|       |
  202|       |                /* If we have not responded and we have a data handler, we need to timeout to enfore client sending the data */
  203|  1.65k|                if (!((HttpResponse<SSL> *) s)->hasResponded() && httpResponseData->inStream) {
  204|  1.65k|                    us_socket_timeout(SSL, (us_socket_t *) s, HTTP_IDLE_TIMEOUT_S);
  205|  1.65k|                }
  206|       |
  207|       |                /* Continue parsing */
  208|  1.65k|                return s;
  209|       |
  210|  1.65k|            }, [httpResponseData](void *user, std::string_view data, bool fin) -> void * {
  211|       |                /* We always get an empty chunk even if there is no data */
  212|  1.65k|                if (httpResponseData->inStream) {
  213|       |
  214|       |                    /* Todo: can this handle timeout for non-post as well? */
  215|  1.65k|                    if (fin) {
  216|       |                        /* If we just got the last chunk (or empty chunk), disable timeout */
  217|  1.65k|                        us_socket_timeout(SSL, (struct us_socket_t *) user, 0);
  218|  1.65k|                    } else {
  219|       |                        /* We still have some more data coming in later, so reset timeout */
  220|       |                        /* Only reset timeout if we got enough bytes (16kb/sec) since last time we reset here */
  221|  1.65k|                        httpResponseData->received_bytes_per_timeout += (unsigned int) data.length();
  222|  1.65k|                        if (httpResponseData->received_bytes_per_timeout >= HTTP_RECEIVE_THROUGHPUT_BYTES * HTTP_IDLE_TIMEOUT_S) {
  223|  1.65k|                            us_socket_timeout(SSL, (struct us_socket_t *) user, HTTP_IDLE_TIMEOUT_S);
  224|  1.65k|                            httpResponseData->received_bytes_per_timeout = 0;
  225|  1.65k|                        }
  226|  1.65k|                    }
  227|       |
  228|       |                    /* We might respond in the handler, so do not change timeout after this */
  229|  1.65k|                    httpResponseData->inStream(data, fin);
  230|       |
  231|       |                    /* Was the socket closed? */
  232|  1.65k|                    if (us_socket_is_closed(SSL, (struct us_socket_t *) user)) {
  233|  1.65k|                        return nullptr;
  234|  1.65k|                    }
  235|       |
  236|       |                    /* We absolutely have to terminate parsing if shutdown */
  237|  1.65k|                    if (us_socket_is_shut_down(SSL, (us_socket_t *) user)) {
  238|  1.65k|                        return nullptr;
  239|  1.65k|                    }
  240|       |
  241|       |                    /* If we were given the last data chunk, reset data handler to ensure following
  242|       |                     * requests on the same socket won't trigger any previously registered behavior */
  243|  1.65k|                    if (fin) {
  244|  1.65k|                        httpResponseData->inStream = nullptr;
  245|  1.65k|                    }
  246|  1.65k|                }
  247|  1.65k|                return user;
  248|  1.65k|            });
  249|       |
  250|       |            /* Mark that we are no longer parsing Http */
  251|  1.65k|            httpContextData->isParsingHttp = false;
  252|       |
  253|       |            /* If we got fullptr that means the parser wants us to close the socket from error (same as calling the errorHandler) */
  254|  1.65k|            if (returnedSocket == FULLPTR) {
  255|       |                /* For errors, we only deliver them "at most once". We don't care if they get halfways delivered or not. */
  256|  1.65k|                us_socket_write(SSL, s, httpErrorResponses[err].data(), (int) httpErrorResponses[err].length(), false);
  257|  1.65k|                us_socket_shutdown(SSL, s);
  258|       |                /* Close any socket on HTTP errors */
  259|  1.65k|                us_socket_close(SSL, s, 0, nullptr);
  260|       |                /* This just makes the following code act as if the socket was closed from error inside the parser. */
  261|  1.65k|                returnedSocket = nullptr;
  262|  1.65k|            }
  263|       |
  264|       |            /* We need to uncork in all cases, except for nullptr (closed socket, or upgraded socket) */
  265|  1.65k|            if (returnedSocket != nullptr) {
  266|       |                /* Timeout on uncork failure */
  267|  1.65k|                auto [written, failed] = ((AsyncSocket<SSL> *) returnedSocket)->uncork();
  268|  1.65k|                if (failed) {
  269|       |                    /* All Http sockets timeout by this, and this behavior match the one in HttpResponse::cork */
  270|       |                    /* Warning: both HTTP_IDLE_TIMEOUT_S and HTTP_TIMEOUT_S are 10 seconds and both are used the same */
  271|  1.65k|                    ((AsyncSocket<SSL> *) s)->timeout(HTTP_IDLE_TIMEOUT_S);
  272|  1.65k|                }
  273|       |
  274|       |                /* We need to check if we should close this socket here now */
  275|  1.65k|                if (httpResponseData->state & HttpResponseData<SSL>::HTTP_CONNECTION_CLOSE) {
  276|  1.65k|                    if ((httpResponseData->state & HttpResponseData<SSL>::HTTP_RESPONSE_PENDING) == 0) {
  277|  1.65k|                        if (((AsyncSocket<SSL> *) s)->getBufferedAmount() == 0) {
  278|  1.65k|                            ((AsyncSocket<SSL> *) s)->shutdown();
  279|       |                            /* We need to force close after sending FIN since we want to hinder
  280|       |                             * clients from keeping to send their huge data */
  281|  1.65k|                            ((AsyncSocket<SSL> *) s)->close();
  282|  1.65k|                        }
  283|  1.65k|                    }
  284|  1.65k|                }
  285|       |
  286|  1.65k|                return (us_socket_t *) returnedSocket;
  287|  1.65k|            }
  288|       |
  289|       |            /* If we upgraded, check here (differ between nullptr close and nullptr upgrade) */
  290|  1.65k|            if (httpContextData->upgradedWebSocket) {
  291|       |                /* This path is only for upgraded websockets */
  292|  1.65k|                AsyncSocket<SSL> *asyncSocket = (AsyncSocket<SSL> *) httpContextData->upgradedWebSocket;
  293|       |
  294|       |                /* Uncork here as well (note: what if we failed to uncork and we then pub/sub before we even upgraded?) */
  295|  1.65k|                auto [written, failed] = asyncSocket->uncork();
  296|       |
  297|       |                /* If we succeeded in uncorking, check if we have sent WebSocket FIN */
  298|  1.65k|                if (!failed) {
  299|  1.65k|                    WebSocketData *webSocketData = (WebSocketData *) asyncSocket->getAsyncSocketData();
  300|  1.65k|                    if (webSocketData->isShuttingDown) {
  301|       |                        /* In that case, also send TCP FIN (this is similar to what we have in ws drain handler) */
  302|  1.65k|                        asyncSocket->shutdown();
  303|  1.65k|                    }
  304|  1.65k|                }
  305|       |
  306|       |                /* Reset upgradedWebSocket before we return */
  307|  1.65k|                httpContextData->upgradedWebSocket = nullptr;
  308|       |
  309|       |                /* Return the new upgraded websocket */
  310|  1.65k|                return (us_socket_t *) asyncSocket;
  311|  1.65k|            }
  312|       |
  313|       |            /* It is okay to uncork a closed socket and we need to */
  314|  1.65k|            ((AsyncSocket<SSL> *) s)->uncork();
  315|       |
  316|       |            /* We cannot return nullptr to the underlying stack in any case */
  317|  1.65k|            return s;
  318|  1.65k|        });
  319|       |
  320|       |        /* Handle HTTP write out (note: SSL_read may trigger this spuriously, the app need to handle spurious calls) */
  321|  1.65k|        us_socket_context_on_writable(SSL, getSocketContext(), [](us_socket_t *s) {
  322|       |
  323|  1.65k|            AsyncSocket<SSL> *asyncSocket = (AsyncSocket<SSL> *) s;
  324|  1.65k|            HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) asyncSocket->getAsyncSocketData();
  325|       |
  326|       |            /* Ask the developer to write data and return success (true) or failure (false), OR skip sending anything and return success (true). */
  327|  1.65k|            if (httpResponseData->onWritable) {
  328|       |                /* We are now writable, so hang timeout again, the user does not have to do anything so we should hang until end or tryEnd rearms timeout */
  329|  1.65k|                us_socket_timeout(SSL, s, 0);
  330|       |
  331|       |                /* We expect the developer to return whether or not write was successful (true).
  332|       |                 * If write was never called, the developer should still return true so that we may drain. */
  333|  1.65k|                bool success = httpResponseData->callOnWritable(httpResponseData->offset);
  334|       |
  335|       |                /* The developer indicated that their onWritable failed. */
  336|  1.65k|                if (!success) {
  337|       |                    /* Skip testing if we can drain anything since that might perform an extra syscall */
  338|  1.65k|                    return s;
  339|  1.65k|                }
  340|       |
  341|       |                /* We don't want to fall through since we don't want to mess with timeout.
  342|       |                 * It makes little sense to drain any backpressure when the user has registered onWritable. */
  343|  1.65k|                return s;
  344|  1.65k|            }
  345|       |
  346|       |            /* Drain any socket buffer, this might empty our backpressure and thus finish the request */
  347|  1.65k|            /*auto [written, failed] = */asyncSocket->write(nullptr, 0, true, 0);
  348|       |
  349|       |            /* Should we close this connection after a response - and is this response really done? */
  350|  1.65k|            if (httpResponseData->state & HttpResponseData<SSL>::HTTP_CONNECTION_CLOSE) {
  351|  1.65k|                if ((httpResponseData->state & HttpResponseData<SSL>::HTTP_RESPONSE_PENDING) == 0) {
  352|  1.65k|                    if (asyncSocket->getBufferedAmount() == 0) {
  353|  1.65k|                        asyncSocket->shutdown();
  354|       |                        /* We need to force close after sending FIN since we want to hinder
  355|       |                         * clients from keeping to send their huge data */
  356|  1.65k|                        asyncSocket->close();
  357|  1.65k|                    }
  358|  1.65k|                }
  359|  1.65k|            }
  360|       |
  361|       |            /* Expect another writable event, or another request within the timeout */
  362|  1.65k|            asyncSocket->timeout(HTTP_IDLE_TIMEOUT_S);
  363|       |
  364|  1.65k|            return s;
  365|  1.65k|        });
  366|       |
  367|       |        /* Handle FIN, HTTP does not support half-closed sockets, so simply close */
  368|  1.65k|        us_socket_context_on_end(SSL, getSocketContext(), [](us_socket_t *s) {
  369|       |
  370|       |            /* We do not care for half closed sockets */
  371|  1.65k|            AsyncSocket<SSL> *asyncSocket = (AsyncSocket<SSL> *) s;
  372|  1.65k|            return asyncSocket->close();
  373|       |
  374|  1.65k|        });
  375|       |
  376|       |        /* Handle socket timeouts, simply close them so to not confuse client with FIN */
  377|  1.65k|        us_socket_context_on_timeout(SSL, getSocketContext(), [](us_socket_t *s) {
  378|       |
  379|       |            /* Force close rather than gracefully shutdown and risk confusing the client with a complete download */
  380|  1.65k|            AsyncSocket<SSL> *asyncSocket = (AsyncSocket<SSL> *) s;
  381|  1.65k|            return asyncSocket->close();
  382|       |
  383|  1.65k|        });
  384|       |
  385|  1.65k|        return this;
  386|  1.65k|    }
_ZN3uWS11HttpContextILb0EE16getSocketContextEv:
   49|  16.5k|    us_socket_context_t *getSocketContext() {
   50|  16.5k|        return (us_socket_context_t *) this;
   51|  16.5k|    }
_ZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tiPciE_clES3_iS4_i:
   68|  1.01M|        us_socket_context_on_open(SSL, getSocketContext(), [](us_socket_t *s, int /*is_client*/, char */*ip*/, int /*ip_length*/) {
   69|       |            /* Any connected socket should timeout until it has a request */
   70|  1.01M|            us_socket_timeout(SSL, s, HTTP_IDLE_TIMEOUT_S);
   71|       |
   72|       |            /* Init socket ext */
   73|  1.01M|            new (us_socket_ext(SSL, s)) HttpResponseData<SSL>;
   74|       |
   75|       |            /* Call filter */
   76|  1.01M|            HttpContextData<SSL> *httpContextData = getSocketContextDataS(s);
   77|  1.01M|            for (auto &f : httpContextData->filterHandlers) {
  ------------------
  |  Branch (77:26): [True: 0, False: 1.01M]
  ------------------
   78|      0|                f((HttpResponse<SSL> *) s, 1);
   79|      0|            }
   80|       |
   81|  1.01M|            return s;
   82|  1.01M|        });
_ZN3uWS11HttpContextILb0EE21getSocketContextDataSEP11us_socket_t:
   61|  2.15M|    static HttpContextData<SSL> *getSocketContextDataS(us_socket_t *s) {
   62|  2.15M|        return (HttpContextData<SSL> *) us_socket_context_ext(SSL, getSocketContext(s));
   63|  2.15M|    }
_ZN3uWS11HttpContextILb0EE16getSocketContextEP11us_socket_t:
   53|  2.15M|    static us_socket_context_t *getSocketContext(us_socket_t *s) {
   54|  2.15M|        return (us_socket_context_t *) us_socket_context(SSL, s);
   55|  2.15M|    }
_ZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tiPvE_clES3_iS4_:
   85|  1.01M|        us_socket_context_on_close(SSL, getSocketContext(), [](us_socket_t *s, int /*code*/, void */*reason*/) {
   86|       |            /* Get socket ext */
   87|  1.01M|            HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) us_socket_ext(SSL, s);
   88|       |
   89|       |            /* Call filter */
   90|  1.01M|            HttpContextData<SSL> *httpContextData = getSocketContextDataS(s);
   91|  1.01M|            for (auto &f : httpContextData->filterHandlers) {
  ------------------
  |  Branch (91:26): [True: 0, False: 1.01M]
  ------------------
   92|      0|                f((HttpResponse<SSL> *) s, -1);
   93|      0|            }
   94|       |
   95|       |            /* Signal broken HTTP request only if we have a pending request */
   96|  1.01M|            if (httpResponseData->onAborted) {
  ------------------
  |  Branch (96:17): [True: 10.1k, False: 999k]
  ------------------
   97|  10.1k|                httpResponseData->onAborted();
   98|  10.1k|            }
   99|       |
  100|       |            /* Destruct socket ext */
  101|  1.01M|            httpResponseData->~HttpResponseData<SSL>();
  102|       |
  103|  1.01M|            return s;
  104|  1.01M|        });
_ZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clES3_S4_i:
  107|   132k|        us_socket_context_on_data(SSL, getSocketContext(), [](us_socket_t *s, char *data, int length) {
  108|       |
  109|       |            // total overhead is about 210k down to 180k
  110|       |            // ~210k req/sec is the original perf with write in data
  111|       |            // ~200k req/sec is with cork and formatting
  112|       |            // ~190k req/sec is with http parsing
  113|       |            // ~180k - 190k req/sec is with varying routing
  114|       |
  115|   132k|            HttpContextData<SSL> *httpContextData = getSocketContextDataS(s);
  116|       |
  117|       |            /* Do not accept any data while in shutdown state */
  118|   132k|            if (us_socket_is_shut_down(SSL, (us_socket_t *) s)) {
  ------------------
  |  Branch (118:17): [True: 0, False: 132k]
  ------------------
  119|      0|                return s;
  120|      0|            }
  121|       |
  122|   132k|            HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) us_socket_ext(SSL, s);
  123|       |
  124|       |            /* Cork this socket */
  125|   132k|            ((AsyncSocket<SSL> *) s)->cork();
  126|       |
  127|       |            /* Mark that we are inside the parser now */
  128|   132k|            httpContextData->isParsingHttp = true;
  129|       |
  130|       |            // clients need to know the cursor after http parse, not servers!
  131|       |            // how far did we read then? we need to know to continue with websocket parsing data? or?
  132|       |
  133|   132k|            void *proxyParser = nullptr;
  134|       |#ifdef UWS_WITH_PROXY
  135|       |            proxyParser = &httpResponseData->proxyParser;
  136|       |#endif
  137|       |
  138|       |            /* The return value is entirely up to us to interpret. The HttpParser only care for whether the returned value is DIFFERENT or not from passed user */
  139|   132k|            auto [err, returnedSocket] = httpResponseData->consumePostPadded(data, (unsigned int) length, s, proxyParser, [httpContextData](void *s, HttpRequest *httpRequest) -> void * {
  140|       |                /* For every request we reset the timeout and hang until user makes action */
  141|       |                /* Warning: if we are in shutdown state, resetting the timer is a security issue! */
  142|   132k|                us_socket_timeout(SSL, (us_socket_t *) s, 0);
  143|       |
  144|       |                /* Reset httpResponse */
  145|   132k|                HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) us_socket_ext(SSL, (us_socket_t *) s);
  146|   132k|                httpResponseData->offset = 0;
  147|       |
  148|       |                /* Are we not ready for another request yet? Terminate the connection. */
  149|   132k|                if (httpResponseData->state & HttpResponseData<SSL>::HTTP_RESPONSE_PENDING) {
  150|   132k|                    us_socket_close(SSL, (us_socket_t *) s, 0, nullptr);
  151|   132k|                    return nullptr;
  152|   132k|                }
  153|       |
  154|       |                /* Mark pending request and emit it */
  155|   132k|                httpResponseData->state = HttpResponseData<SSL>::HTTP_RESPONSE_PENDING;
  156|       |
  157|       |                /* Mark this response as connectionClose if ancient or connection: close */
  158|   132k|                if (httpRequest->isAncient() || httpRequest->getHeader("connection").length() == 5) {
  159|   132k|                    httpResponseData->state |= HttpResponseData<SSL>::HTTP_CONNECTION_CLOSE;
  160|   132k|                }
  161|       |
  162|       |                /* Select the router based on SNI (only possible for SSL) */
  163|   132k|                auto *selectedRouter = &httpContextData->router;
  164|   132k|                if constexpr (SSL) {
  165|   132k|                    void *domainRouter = us_socket_server_name_userdata(SSL, (struct us_socket_t *) s);
  166|   132k|                    if (domainRouter) {
  167|   132k|                        selectedRouter = (decltype(selectedRouter)) domainRouter;
  168|   132k|                    }
  169|   132k|                }
  170|       |
  171|       |                /* Route the method and URL */
  172|   132k|                selectedRouter->getUserData() = {(HttpResponse<SSL> *) s, httpRequest};
  173|   132k|                if (!selectedRouter->route(httpRequest->getCaseSensitiveMethod(), httpRequest->getUrl())) {
  174|       |                    /* We have to force close this socket as we have no handler for it */
  175|   132k|                    us_socket_close(SSL, (us_socket_t *) s, 0, nullptr);
  176|   132k|                    return nullptr;
  177|   132k|                }
  178|       |
  179|       |                /* First of all we need to check if this socket was deleted due to upgrade */
  180|   132k|                if (httpContextData->upgradedWebSocket) {
  181|       |                    /* We differ between closed and upgraded below */
  182|   132k|                    return nullptr;
  183|   132k|                }
  184|       |
  185|       |                /* Was the socket closed? */
  186|   132k|                if (us_socket_is_closed(SSL, (struct us_socket_t *) s)) {
  187|   132k|                    return nullptr;
  188|   132k|                }
  189|       |
  190|       |                /* We absolutely have to terminate parsing if shutdown */
  191|   132k|                if (us_socket_is_shut_down(SSL, (us_socket_t *) s)) {
  192|   132k|                    return nullptr;
  193|   132k|                }
  194|       |
  195|       |                /* Returning from a request handler without responding or attaching an onAborted handler is ill-use */
  196|   132k|                if (!((HttpResponse<SSL> *) s)->hasResponded() && !httpResponseData->onAborted) {
  197|       |                    /* Throw exception here? */
  198|   132k|                    std::cerr << "Error: Returning from a request handler without responding or attaching an abort handler is forbidden!" << std::endl;
  199|   132k|                    std::terminate();
  200|   132k|                }
  201|       |
  202|       |                /* If we have not responded and we have a data handler, we need to timeout to enfore client sending the data */
  203|   132k|                if (!((HttpResponse<SSL> *) s)->hasResponded() && httpResponseData->inStream) {
  204|   132k|                    us_socket_timeout(SSL, (us_socket_t *) s, HTTP_IDLE_TIMEOUT_S);
  205|   132k|                }
  206|       |
  207|       |                /* Continue parsing */
  208|   132k|                return s;
  209|       |
  210|   132k|            }, [httpResponseData](void *user, std::string_view data, bool fin) -> void * {
  211|       |                /* We always get an empty chunk even if there is no data */
  212|   132k|                if (httpResponseData->inStream) {
  213|       |
  214|       |                    /* Todo: can this handle timeout for non-post as well? */
  215|   132k|                    if (fin) {
  216|       |                        /* If we just got the last chunk (or empty chunk), disable timeout */
  217|   132k|                        us_socket_timeout(SSL, (struct us_socket_t *) user, 0);
  218|   132k|                    } else {
  219|       |                        /* We still have some more data coming in later, so reset timeout */
  220|       |                        /* Only reset timeout if we got enough bytes (16kb/sec) since last time we reset here */
  221|   132k|                        httpResponseData->received_bytes_per_timeout += (unsigned int) data.length();
  222|   132k|                        if (httpResponseData->received_bytes_per_timeout >= HTTP_RECEIVE_THROUGHPUT_BYTES * HTTP_IDLE_TIMEOUT_S) {
  223|   132k|                            us_socket_timeout(SSL, (struct us_socket_t *) user, HTTP_IDLE_TIMEOUT_S);
  224|   132k|                            httpResponseData->received_bytes_per_timeout = 0;
  225|   132k|                        }
  226|   132k|                    }
  227|       |
  228|       |                    /* We might respond in the handler, so do not change timeout after this */
  229|   132k|                    httpResponseData->inStream(data, fin);
  230|       |
  231|       |                    /* Was the socket closed? */
  232|   132k|                    if (us_socket_is_closed(SSL, (struct us_socket_t *) user)) {
  233|   132k|                        return nullptr;
  234|   132k|                    }
  235|       |
  236|       |                    /* We absolutely have to terminate parsing if shutdown */
  237|   132k|                    if (us_socket_is_shut_down(SSL, (us_socket_t *) user)) {
  238|   132k|                        return nullptr;
  239|   132k|                    }
  240|       |
  241|       |                    /* If we were given the last data chunk, reset data handler to ensure following
  242|       |                     * requests on the same socket won't trigger any previously registered behavior */
  243|   132k|                    if (fin) {
  244|   132k|                        httpResponseData->inStream = nullptr;
  245|   132k|                    }
  246|   132k|                }
  247|   132k|                return user;
  248|   132k|            });
  249|       |
  250|       |            /* Mark that we are no longer parsing Http */
  251|   132k|            httpContextData->isParsingHttp = false;
  252|       |
  253|       |            /* If we got fullptr that means the parser wants us to close the socket from error (same as calling the errorHandler) */
  254|   132k|            if (returnedSocket == FULLPTR) {
  ------------------
  |  Branch (254:17): [True: 88.7k, False: 44.2k]
  ------------------
  255|       |                /* For errors, we only deliver them "at most once". We don't care if they get halfways delivered or not. */
  256|  88.7k|                us_socket_write(SSL, s, httpErrorResponses[err].data(), (int) httpErrorResponses[err].length(), false);
  257|  88.7k|                us_socket_shutdown(SSL, s);
  258|       |                /* Close any socket on HTTP errors */
  259|  88.7k|                us_socket_close(SSL, s, 0, nullptr);
  260|       |                /* This just makes the following code act as if the socket was closed from error inside the parser. */
  261|  88.7k|                returnedSocket = nullptr;
  262|  88.7k|            }
  263|       |
  264|       |            /* We need to uncork in all cases, except for nullptr (closed socket, or upgraded socket) */
  265|   132k|            if (returnedSocket != nullptr) {
  ------------------
  |  Branch (265:17): [True: 40.0k, False: 92.9k]
  ------------------
  266|       |                /* Timeout on uncork failure */
  267|  40.0k|                auto [written, failed] = ((AsyncSocket<SSL> *) returnedSocket)->uncork();
  268|  40.0k|                if (failed) {
  ------------------
  |  Branch (268:21): [True: 12.6k, False: 27.4k]
  ------------------
  269|       |                    /* All Http sockets timeout by this, and this behavior match the one in HttpResponse::cork */
  270|       |                    /* Warning: both HTTP_IDLE_TIMEOUT_S and HTTP_TIMEOUT_S are 10 seconds and both are used the same */
  271|  12.6k|                    ((AsyncSocket<SSL> *) s)->timeout(HTTP_IDLE_TIMEOUT_S);
  272|  12.6k|                }
  273|       |
  274|       |                /* We need to check if we should close this socket here now */
  275|  40.0k|                if (httpResponseData->state & HttpResponseData<SSL>::HTTP_CONNECTION_CLOSE) {
  ------------------
  |  Branch (275:21): [True: 3.40k, False: 36.6k]
  ------------------
  276|  3.40k|                    if ((httpResponseData->state & HttpResponseData<SSL>::HTTP_RESPONSE_PENDING) == 0) {
  ------------------
  |  Branch (276:25): [True: 841, False: 2.56k]
  ------------------
  277|    841|                        if (((AsyncSocket<SSL> *) s)->getBufferedAmount() == 0) {
  ------------------
  |  Branch (277:29): [True: 200, False: 641]
  ------------------
  278|    200|                            ((AsyncSocket<SSL> *) s)->shutdown();
  279|       |                            /* We need to force close after sending FIN since we want to hinder
  280|       |                             * clients from keeping to send their huge data */
  281|    200|                            ((AsyncSocket<SSL> *) s)->close();
  282|    200|                        }
  283|    841|                    }
  284|  3.40k|                }
  285|       |
  286|  40.0k|                return (us_socket_t *) returnedSocket;
  287|  40.0k|            }
  288|       |
  289|       |            /* If we upgraded, check here (differ between nullptr close and nullptr upgrade) */
  290|  92.9k|            if (httpContextData->upgradedWebSocket) {
  ------------------
  |  Branch (290:17): [True: 0, False: 92.9k]
  ------------------
  291|       |                /* This path is only for upgraded websockets */
  292|      0|                AsyncSocket<SSL> *asyncSocket = (AsyncSocket<SSL> *) httpContextData->upgradedWebSocket;
  293|       |
  294|       |                /* Uncork here as well (note: what if we failed to uncork and we then pub/sub before we even upgraded?) */
  295|      0|                auto [written, failed] = asyncSocket->uncork();
  296|       |
  297|       |                /* If we succeeded in uncorking, check if we have sent WebSocket FIN */
  298|      0|                if (!failed) {
  ------------------
  |  Branch (298:21): [True: 0, False: 0]
  ------------------
  299|      0|                    WebSocketData *webSocketData = (WebSocketData *) asyncSocket->getAsyncSocketData();
  300|      0|                    if (webSocketData->isShuttingDown) {
  ------------------
  |  Branch (300:25): [True: 0, False: 0]
  ------------------
  301|       |                        /* In that case, also send TCP FIN (this is similar to what we have in ws drain handler) */
  302|      0|                        asyncSocket->shutdown();
  303|      0|                    }
  304|      0|                }
  305|       |
  306|       |                /* Reset upgradedWebSocket before we return */
  307|      0|                httpContextData->upgradedWebSocket = nullptr;
  308|       |
  309|       |                /* Return the new upgraded websocket */
  310|      0|                return (us_socket_t *) asyncSocket;
  311|      0|            }
  312|       |
  313|       |            /* It is okay to uncork a closed socket and we need to */
  314|  92.9k|            ((AsyncSocket<SSL> *) s)->uncork();
  315|       |
  316|       |            /* We cannot return nullptr to the underlying stack in any case */
  317|  92.9k|            return s;
  318|  92.9k|        });
_ZZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clES3_S4_iENKUlPvPNS_11HttpRequestEE_clES6_S8_:
  139|  27.4k|            auto [err, returnedSocket] = httpResponseData->consumePostPadded(data, (unsigned int) length, s, proxyParser, [httpContextData](void *s, HttpRequest *httpRequest) -> void * {
  140|       |                /* For every request we reset the timeout and hang until user makes action */
  141|       |                /* Warning: if we are in shutdown state, resetting the timer is a security issue! */
  142|  27.4k|                us_socket_timeout(SSL, (us_socket_t *) s, 0);
  143|       |
  144|       |                /* Reset httpResponse */
  145|  27.4k|                HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) us_socket_ext(SSL, (us_socket_t *) s);
  146|  27.4k|                httpResponseData->offset = 0;
  147|       |
  148|       |                /* Are we not ready for another request yet? Terminate the connection. */
  149|  27.4k|                if (httpResponseData->state & HttpResponseData<SSL>::HTTP_RESPONSE_PENDING) {
  ------------------
  |  Branch (149:21): [True: 1.22k, False: 26.1k]
  ------------------
  150|  1.22k|                    us_socket_close(SSL, (us_socket_t *) s, 0, nullptr);
  151|  1.22k|                    return nullptr;
  152|  1.22k|                }
  153|       |
  154|       |                /* Mark pending request and emit it */
  155|  26.1k|                httpResponseData->state = HttpResponseData<SSL>::HTTP_RESPONSE_PENDING;
  156|       |
  157|       |                /* Mark this response as connectionClose if ancient or connection: close */
  158|  26.1k|                if (httpRequest->isAncient() || httpRequest->getHeader("connection").length() == 5) {
  ------------------
  |  Branch (158:21): [True: 0, False: 26.1k]
  |  Branch (158:21): [True: 3.82k, False: 22.3k]
  |  Branch (158:49): [True: 3.82k, False: 22.3k]
  ------------------
  159|  3.82k|                    httpResponseData->state |= HttpResponseData<SSL>::HTTP_CONNECTION_CLOSE;
  160|  3.82k|                }
  161|       |
  162|       |                /* Select the router based on SNI (only possible for SSL) */
  163|  26.1k|                auto *selectedRouter = &httpContextData->router;
  164|  26.1k|                if constexpr (SSL) {
  ------------------
  |  Branch (164:31): [Folded - Ignored]
  ------------------
  165|  26.1k|                    void *domainRouter = us_socket_server_name_userdata(SSL, (struct us_socket_t *) s);
  166|  26.1k|                    if (domainRouter) {
  167|  26.1k|                        selectedRouter = (decltype(selectedRouter)) domainRouter;
  168|  26.1k|                    }
  169|  26.1k|                }
  170|       |
  171|       |                /* Route the method and URL */
  172|  26.1k|                selectedRouter->getUserData() = {(HttpResponse<SSL> *) s, httpRequest};
  173|  26.1k|                if (!selectedRouter->route(httpRequest->getCaseSensitiveMethod(), httpRequest->getUrl())) {
  ------------------
  |  Branch (173:21): [True: 2.93k, False: 23.2k]
  ------------------
  174|       |                    /* We have to force close this socket as we have no handler for it */
  175|  2.93k|                    us_socket_close(SSL, (us_socket_t *) s, 0, nullptr);
  176|  2.93k|                    return nullptr;
  177|  2.93k|                }
  178|       |
  179|       |                /* First of all we need to check if this socket was deleted due to upgrade */
  180|  23.2k|                if (httpContextData->upgradedWebSocket) {
  ------------------
  |  Branch (180:21): [True: 0, False: 23.2k]
  ------------------
  181|       |                    /* We differ between closed and upgraded below */
  182|      0|                    return nullptr;
  183|      0|                }
  184|       |
  185|       |                /* Was the socket closed? */
  186|  23.2k|                if (us_socket_is_closed(SSL, (struct us_socket_t *) s)) {
  ------------------
  |  Branch (186:21): [True: 0, False: 23.2k]
  ------------------
  187|      0|                    return nullptr;
  188|      0|                }
  189|       |
  190|       |                /* We absolutely have to terminate parsing if shutdown */
  191|  23.2k|                if (us_socket_is_shut_down(SSL, (us_socket_t *) s)) {
  ------------------
  |  Branch (191:21): [True: 0, False: 23.2k]
  ------------------
  192|      0|                    return nullptr;
  193|      0|                }
  194|       |
  195|       |                /* Returning from a request handler without responding or attaching an onAborted handler is ill-use */
  196|  23.2k|                if (!((HttpResponse<SSL> *) s)->hasResponded() && !httpResponseData->onAborted) {
  ------------------
  |  Branch (196:21): [True: 23.2k, False: 0]
  |  Branch (196:67): [True: 0, False: 23.2k]
  ------------------
  197|       |                    /* Throw exception here? */
  198|      0|                    std::cerr << "Error: Returning from a request handler without responding or attaching an abort handler is forbidden!" << std::endl;
  199|      0|                    std::terminate();
  200|      0|                }
  201|       |
  202|       |                /* If we have not responded and we have a data handler, we need to timeout to enfore client sending the data */
  203|  23.2k|                if (!((HttpResponse<SSL> *) s)->hasResponded() && httpResponseData->inStream) {
  ------------------
  |  Branch (203:21): [True: 23.2k, False: 0]
  |  Branch (203:67): [True: 0, False: 23.2k]
  ------------------
  204|      0|                    us_socket_timeout(SSL, (us_socket_t *) s, HTTP_IDLE_TIMEOUT_S);
  205|      0|                }
  206|       |
  207|       |                /* Continue parsing */
  208|  23.2k|                return s;
  209|       |
  210|  23.2k|            }, [httpResponseData](void *user, std::string_view data, bool fin) -> void * {
_ZZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clES3_S4_iENKUlPvNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEbE_clES6_SB_b:
  210|  23.2k|            }, [httpResponseData](void *user, std::string_view data, bool fin) -> void * {
  211|       |                /* We always get an empty chunk even if there is no data */
  212|  23.2k|                if (httpResponseData->inStream) {
  ------------------
  |  Branch (212:21): [True: 0, False: 23.2k]
  ------------------
  213|       |
  214|       |                    /* Todo: can this handle timeout for non-post as well? */
  215|      0|                    if (fin) {
  ------------------
  |  Branch (215:25): [True: 0, False: 0]
  ------------------
  216|       |                        /* If we just got the last chunk (or empty chunk), disable timeout */
  217|      0|                        us_socket_timeout(SSL, (struct us_socket_t *) user, 0);
  218|      0|                    } else {
  219|       |                        /* We still have some more data coming in later, so reset timeout */
  220|       |                        /* Only reset timeout if we got enough bytes (16kb/sec) since last time we reset here */
  221|      0|                        httpResponseData->received_bytes_per_timeout += (unsigned int) data.length();
  222|      0|                        if (httpResponseData->received_bytes_per_timeout >= HTTP_RECEIVE_THROUGHPUT_BYTES * HTTP_IDLE_TIMEOUT_S) {
  ------------------
  |  Branch (222:29): [True: 0, False: 0]
  ------------------
  223|      0|                            us_socket_timeout(SSL, (struct us_socket_t *) user, HTTP_IDLE_TIMEOUT_S);
  224|      0|                            httpResponseData->received_bytes_per_timeout = 0;
  225|      0|                        }
  226|      0|                    }
  227|       |
  228|       |                    /* We might respond in the handler, so do not change timeout after this */
  229|      0|                    httpResponseData->inStream(data, fin);
  230|       |
  231|       |                    /* Was the socket closed? */
  232|      0|                    if (us_socket_is_closed(SSL, (struct us_socket_t *) user)) {
  ------------------
  |  Branch (232:25): [True: 0, False: 0]
  ------------------
  233|      0|                        return nullptr;
  234|      0|                    }
  235|       |
  236|       |                    /* We absolutely have to terminate parsing if shutdown */
  237|      0|                    if (us_socket_is_shut_down(SSL, (us_socket_t *) user)) {
  ------------------
  |  Branch (237:25): [True: 0, False: 0]
  ------------------
  238|      0|                        return nullptr;
  239|      0|                    }
  240|       |
  241|       |                    /* If we were given the last data chunk, reset data handler to ensure following
  242|       |                     * requests on the same socket won't trigger any previously registered behavior */
  243|      0|                    if (fin) {
  ------------------
  |  Branch (243:25): [True: 0, False: 0]
  ------------------
  244|      0|                        httpResponseData->inStream = nullptr;
  245|      0|                    }
  246|      0|                }
  247|  23.2k|                return user;
  248|  23.2k|            });
_ZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tE_clES3_:
  321|  10.5k|        us_socket_context_on_writable(SSL, getSocketContext(), [](us_socket_t *s) {
  322|       |
  323|  10.5k|            AsyncSocket<SSL> *asyncSocket = (AsyncSocket<SSL> *) s;
  324|  10.5k|            HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) asyncSocket->getAsyncSocketData();
  325|       |
  326|       |            /* Ask the developer to write data and return success (true) or failure (false), OR skip sending anything and return success (true). */
  327|  10.5k|            if (httpResponseData->onWritable) {
  ------------------
  |  Branch (327:17): [True: 0, False: 10.5k]
  ------------------
  328|       |                /* We are now writable, so hang timeout again, the user does not have to do anything so we should hang until end or tryEnd rearms timeout */
  329|      0|                us_socket_timeout(SSL, s, 0);
  330|       |
  331|       |                /* We expect the developer to return whether or not write was successful (true).
  332|       |                 * If write was never called, the developer should still return true so that we may drain. */
  333|      0|                bool success = httpResponseData->callOnWritable(httpResponseData->offset);
  334|       |
  335|       |                /* The developer indicated that their onWritable failed. */
  336|      0|                if (!success) {
  ------------------
  |  Branch (336:21): [True: 0, False: 0]
  ------------------
  337|       |                    /* Skip testing if we can drain anything since that might perform an extra syscall */
  338|      0|                    return s;
  339|      0|                }
  340|       |
  341|       |                /* We don't want to fall through since we don't want to mess with timeout.
  342|       |                 * It makes little sense to drain any backpressure when the user has registered onWritable. */
  343|      0|                return s;
  344|      0|            }
  345|       |
  346|       |            /* Drain any socket buffer, this might empty our backpressure and thus finish the request */
  347|  10.5k|            /*auto [written, failed] = */asyncSocket->write(nullptr, 0, true, 0);
  348|       |
  349|       |            /* Should we close this connection after a response - and is this response really done? */
  350|  10.5k|            if (httpResponseData->state & HttpResponseData<SSL>::HTTP_CONNECTION_CLOSE) {
  ------------------
  |  Branch (350:17): [True: 3.01k, False: 7.49k]
  ------------------
  351|  3.01k|                if ((httpResponseData->state & HttpResponseData<SSL>::HTTP_RESPONSE_PENDING) == 0) {
  ------------------
  |  Branch (351:21): [True: 2.79k, False: 215]
  ------------------
  352|  2.79k|                    if (asyncSocket->getBufferedAmount() == 0) {
  ------------------
  |  Branch (352:25): [True: 1.54k, False: 1.25k]
  ------------------
  353|  1.54k|                        asyncSocket->shutdown();
  354|       |                        /* We need to force close after sending FIN since we want to hinder
  355|       |                         * clients from keeping to send their huge data */
  356|  1.54k|                        asyncSocket->close();
  357|  1.54k|                    }
  358|  2.79k|                }
  359|  3.01k|            }
  360|       |
  361|       |            /* Expect another writable event, or another request within the timeout */
  362|  10.5k|            asyncSocket->timeout(HTTP_IDLE_TIMEOUT_S);
  363|       |
  364|  10.5k|            return s;
  365|  10.5k|        });
_ZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tE0_clES3_:
  368|  26.0k|        us_socket_context_on_end(SSL, getSocketContext(), [](us_socket_t *s) {
  369|       |
  370|       |            /* We do not care for half closed sockets */
  371|  26.0k|            AsyncSocket<SSL> *asyncSocket = (AsyncSocket<SSL> *) s;
  372|  26.0k|            return asyncSocket->close();
  373|       |
  374|  26.0k|        });
_ZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tE1_clES3_:
  377|  1.79k|        us_socket_context_on_timeout(SSL, getSocketContext(), [](us_socket_t *s) {
  378|       |
  379|       |            /* Force close rather than gracefully shutdown and risk confusing the client with a complete download */
  380|  1.79k|            AsyncSocket<SSL> *asyncSocket = (AsyncSocket<SSL> *) s;
  381|  1.79k|            return asyncSocket->close();
  382|       |
  383|  1.79k|        });
_ZN3uWS11HttpContextILb0EE4freeEv:
  405|  1.65k|    void free() {
  406|       |        /* Destruct socket context data */
  407|  1.65k|        HttpContextData<SSL> *httpContextData = getSocketContextData();
  408|  1.65k|        httpContextData->~HttpContextData<SSL>();
  409|       |
  410|       |        /* Free the socket context in whole */
  411|  1.65k|        us_socket_context_free(SSL, getSocketContext());
  412|  1.65k|    }
_ZN3uWS11HttpContextILb0EE20getSocketContextDataEv:
   57|  3.31k|    HttpContextData<SSL> *getSocketContextData() {
   58|  3.31k|        return (HttpContextData<SSL> *) us_socket_context_ext(SSL, getSocketContext());
   59|  3.31k|    }
_ZN3uWS11HttpContextILb0EE6onHttpENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEES8_ON5ofats13any_invocableIFvPNS_12HttpResponseILb0EEEPNS_11HttpRequestEEEEb:
  419|  1.65k|    void onHttp(std::string method, std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler, bool upgrade = false) {
  420|  1.65k|        HttpContextData<SSL> *httpContextData = getSocketContextData();
  421|       |
  422|       |        /* Todo: This is ugly, fix */
  423|  1.65k|        std::vector<std::string> methods;
  424|  1.65k|        if (method == "*") {
  ------------------
  |  Branch (424:13): [True: 0, False: 1.65k]
  ------------------
  425|      0|            methods = httpContextData->currentRouter->upperCasedMethods;
  426|  1.65k|        } else {
  427|  1.65k|            methods = {method};
  428|  1.65k|        }
  429|       |
  430|  1.65k|        uint32_t priority = method == "*" ? httpContextData->currentRouter->LOW_PRIORITY : (upgrade ? httpContextData->currentRouter->HIGH_PRIORITY : httpContextData->currentRouter->MEDIUM_PRIORITY);
  ------------------
  |  Branch (430:29): [True: 0, False: 1.65k]
  |  Branch (430:93): [True: 0, False: 1.65k]
  ------------------
  431|       |
  432|       |        /* If we are passed nullptr then remove this */
  433|  1.65k|        if (!handler) {
  ------------------
  |  Branch (433:13): [True: 0, False: 1.65k]
  ------------------
  434|      0|            httpContextData->currentRouter->remove(methods[0], pattern, priority);
  435|      0|            return;
  436|      0|        }
  437|       |
  438|  1.65k|        httpContextData->currentRouter->add(methods, pattern, [handler = std::move(handler)](auto *r) mutable {
  439|  1.65k|            auto user = r->getUserData();
  440|  1.65k|            user.httpRequest->setYield(false);
  441|  1.65k|            user.httpRequest->setParameters(r->getParameters());
  442|       |
  443|       |            /* Middleware? Automatically respond to expectations */
  444|  1.65k|            std::string_view expect = user.httpRequest->getHeader("expect");
  445|  1.65k|            if (expect.length() && expect == "100-continue") {
  446|  1.65k|                user.httpResponse->writeContinue();
  447|  1.65k|            }
  448|       |
  449|  1.65k|            handler(user.httpResponse, user.httpRequest);
  450|       |
  451|       |            /* If any handler yielded, the router will keep looking for a suitable handler. */
  452|  1.65k|            if (user.httpRequest->getYield()) {
  453|  1.65k|                return false;
  454|  1.65k|            }
  455|  1.65k|            return true;
  456|  1.65k|        }, priority);
  457|  1.65k|    }
_ZZN3uWS11HttpContextILb0EE6onHttpENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEES8_ON5ofats13any_invocableIFvPNS_12HttpResponseILb0EEEPNS_11HttpRequestEEEEbENUlPT_E_clINS_10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEEEEEDaSK_:
  438|  23.2k|        httpContextData->currentRouter->add(methods, pattern, [handler = std::move(handler)](auto *r) mutable {
  439|  23.2k|            auto user = r->getUserData();
  440|  23.2k|            user.httpRequest->setYield(false);
  441|  23.2k|            user.httpRequest->setParameters(r->getParameters());
  442|       |
  443|       |            /* Middleware? Automatically respond to expectations */
  444|  23.2k|            std::string_view expect = user.httpRequest->getHeader("expect");
  445|  23.2k|            if (expect.length() && expect == "100-continue") {
  ------------------
  |  Branch (445:17): [True: 0, False: 23.2k]
  |  Branch (445:36): [True: 0, False: 0]
  ------------------
  446|      0|                user.httpResponse->writeContinue();
  447|      0|            }
  448|       |
  449|  23.2k|            handler(user.httpResponse, user.httpRequest);
  450|       |
  451|       |            /* If any handler yielded, the router will keep looking for a suitable handler. */
  452|  23.2k|            if (user.httpRequest->getYield()) {
  ------------------
  |  Branch (452:17): [True: 0, False: 23.2k]
  ------------------
  453|      0|                return false;
  454|      0|            }
  455|  23.2k|            return true;
  456|  23.2k|        }, priority);
_ZN3uWS11HttpContextILb0EE6listenEPKcii:
  460|  1.65k|    us_listen_socket_t *listen(const char *host, int port, int options) {
  461|  1.65k|        return us_socket_context_listen(SSL, getSocketContext(), host, port, options, sizeof(HttpResponseData<SSL>));
  462|  1.65k|    }

_ZN3uWS10HttpParser17consumePostPaddedEPcjPvS2_ON5ofats13any_invocableIFS2_S2_PNS_11HttpRequestEEEEONS4_IFS2_S2_NSt3__117basic_string_viewIcNSA_11char_traitsIcEEEEbEEE:
  527|   132k|    std::pair<unsigned int, void *> consumePostPadded(char *data, unsigned int length, void *user, void *reserved, MoveOnlyFunction<void *(void *, HttpRequest *)> &&requestHandler, MoveOnlyFunction<void *(void *, std::string_view, bool)> &&dataHandler) {
  528|       |
  529|       |        /* This resets BloomFilter by construction, but later we also reset it again.
  530|       |         * Optimize this to skip resetting twice (req could be made global) */
  531|   132k|        HttpRequest req;
  532|       |
  533|   132k|        if (remainingStreamingBytes) {
  ------------------
  |  Branch (533:13): [True: 0, False: 132k]
  ------------------
  534|       |
  535|       |            /* It's either chunked or with a content-length */
  536|      0|            if (isParsingChunkedEncoding(remainingStreamingBytes)) {
  ------------------
  |  Branch (536:17): [True: 0, False: 0]
  ------------------
  537|      0|                std::string_view dataToConsume(data, length);
  538|      0|                for (auto chunk : uWS::ChunkIterator(&dataToConsume, &remainingStreamingBytes)) {
  ------------------
  |  Branch (538:33): [True: 0, False: 0]
  ------------------
  539|      0|                    dataHandler(user, chunk, chunk.length() == 0);
  540|      0|                }
  541|      0|                if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) {
  ------------------
  |  Branch (541:21): [True: 0, False: 0]
  ------------------
  542|      0|                    return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  543|      0|                }
  544|      0|                data = (char *) dataToConsume.data();
  545|      0|                length = (unsigned int) dataToConsume.length();
  546|      0|            } else {
  547|       |                // this is exactly the same as below!
  548|       |                // todo: refactor this
  549|      0|                if (remainingStreamingBytes >= length) {
  ------------------
  |  Branch (549:21): [True: 0, False: 0]
  ------------------
  550|      0|                    void *returnedUser = dataHandler(user, std::string_view(data, length), remainingStreamingBytes == length);
  551|      0|                    remainingStreamingBytes -= length;
  552|      0|                    return {0, returnedUser};
  553|      0|                } else {
  554|      0|                    void *returnedUser = dataHandler(user, std::string_view(data, remainingStreamingBytes), true);
  555|       |
  556|      0|                    data += remainingStreamingBytes;
  557|      0|                    length -= remainingStreamingBytes;
  558|       |
  559|      0|                    remainingStreamingBytes = 0;
  560|       |
  561|      0|                    if (returnedUser != user) {
  ------------------
  |  Branch (561:25): [True: 0, False: 0]
  ------------------
  562|      0|                        return {0, returnedUser};
  563|      0|                    }
  564|      0|                }
  565|      0|            }
  566|       |
  567|   132k|        } else if (fallback.length()) {
  ------------------
  |  Branch (567:20): [True: 25.4k, False: 107k]
  ------------------
  568|  25.4k|            unsigned int had = (unsigned int) fallback.length();
  569|       |
  570|  25.4k|            size_t maxCopyDistance = std::min<size_t>(MAX_FALLBACK_SIZE - fallback.length(), (size_t) length);
  571|       |
  572|       |            /* We don't want fallback to be short string optimized, since we want to move it */
  573|  25.4k|            fallback.reserve(fallback.length() + maxCopyDistance + std::max<unsigned int>(MINIMUM_HTTP_POST_PADDING, sizeof(std::string)));
  574|  25.4k|            fallback.append(data, maxCopyDistance);
  575|       |
  576|       |            // break here on break
  577|  25.4k|            std::pair<unsigned int, void *> consumed = fenceAndConsumePostPadded<true>(fallback.data(), (unsigned int) fallback.length(), user, reserved, &req, requestHandler, dataHandler);
  578|  25.4k|            if (consumed.second != user) {
  ------------------
  |  Branch (578:17): [True: 3.13k, False: 22.3k]
  ------------------
  579|  3.13k|                return consumed;
  580|  3.13k|            }
  581|       |
  582|  22.3k|            if (consumed.first) {
  ------------------
  |  Branch (582:17): [True: 7.45k, False: 14.8k]
  ------------------
  583|       |
  584|       |                /* This logic assumes that we consumed everything in fallback buffer.
  585|       |                 * This is critically important, as we will get an integer overflow in case
  586|       |                 * of "had" being larger than what we consumed, and that we would drop data */
  587|  7.45k|                fallback.clear();
  588|  7.45k|                data += consumed.first - had;
  589|  7.45k|                length -= consumed.first - had;
  590|       |
  591|  7.45k|                if (remainingStreamingBytes) {
  ------------------
  |  Branch (591:21): [True: 0, False: 7.45k]
  ------------------
  592|       |                    /* It's either chunked or with a content-length */
  593|      0|                    if (isParsingChunkedEncoding(remainingStreamingBytes)) {
  ------------------
  |  Branch (593:25): [True: 0, False: 0]
  ------------------
  594|      0|                        std::string_view dataToConsume(data, length);
  595|      0|                        for (auto chunk : uWS::ChunkIterator(&dataToConsume, &remainingStreamingBytes)) {
  ------------------
  |  Branch (595:41): [True: 0, False: 0]
  ------------------
  596|      0|                            dataHandler(user, chunk, chunk.length() == 0);
  597|      0|                        }
  598|      0|                        if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) {
  ------------------
  |  Branch (598:29): [True: 0, False: 0]
  ------------------
  599|      0|                            return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  600|      0|                        }
  601|      0|                        data = (char *) dataToConsume.data();
  602|      0|                        length = (unsigned int) dataToConsume.length();
  603|      0|                    } else {
  604|       |                        // this is exactly the same as above!
  605|      0|                        if (remainingStreamingBytes >= (unsigned int) length) {
  ------------------
  |  Branch (605:29): [True: 0, False: 0]
  ------------------
  606|      0|                            void *returnedUser = dataHandler(user, std::string_view(data, length), remainingStreamingBytes == (unsigned int) length);
  607|      0|                            remainingStreamingBytes -= length;
  608|      0|                            return {0, returnedUser};
  609|      0|                        } else {
  610|      0|                            void *returnedUser = dataHandler(user, std::string_view(data, remainingStreamingBytes), true);
  611|       |
  612|      0|                            data += remainingStreamingBytes;
  613|      0|                            length -= remainingStreamingBytes;
  614|       |
  615|      0|                            remainingStreamingBytes = 0;
  616|       |
  617|      0|                            if (returnedUser != user) {
  ------------------
  |  Branch (617:33): [True: 0, False: 0]
  ------------------
  618|      0|                                return {0, returnedUser};
  619|      0|                            }
  620|      0|                        }
  621|      0|                    }
  622|      0|                }
  623|       |
  624|  14.8k|            } else {
  625|  14.8k|                if (fallback.length() == MAX_FALLBACK_SIZE) {
  ------------------
  |  Branch (625:21): [True: 216, False: 14.6k]
  ------------------
  626|    216|                    return {HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE, FULLPTR};
  627|    216|                }
  628|  14.6k|                return {0, user};
  629|  14.8k|            }
  630|  22.3k|        }
  631|       |
  632|   114k|        std::pair<unsigned int, void *> consumed = fenceAndConsumePostPadded<false>(data, length, user, reserved, &req, requestHandler, dataHandler);
  633|   114k|        if (consumed.second != user) {
  ------------------
  |  Branch (633:13): [True: 89.5k, False: 25.4k]
  ------------------
  634|  89.5k|            return consumed;
  635|  89.5k|        }
  636|       |
  637|  25.4k|        data += consumed.first;
  638|  25.4k|        length -= consumed.first;
  639|       |
  640|  25.4k|        if (length) {
  ------------------
  |  Branch (640:13): [True: 16.4k, False: 8.99k]
  ------------------
  641|  16.4k|            if (length < MAX_FALLBACK_SIZE) {
  ------------------
  |  Branch (641:17): [True: 16.4k, False: 0]
  ------------------
  642|  16.4k|                fallback.append(data, length);
  643|  16.4k|            } else {
  644|      0|                return {HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE, FULLPTR};
  645|      0|            }
  646|  16.4k|        }
  647|       |
  648|       |        // added for now
  649|  25.4k|        return {0, user};
  650|  25.4k|    }
_ZN3uWS10HttpParser25fenceAndConsumePostPaddedILi1EEENSt3__14pairIjPvEEPcjS4_S4_PNS_11HttpRequestERN5ofats13any_invocableIFS4_S4_S8_EEERNSA_IFS4_S4_NS2_17basic_string_viewIcNS2_11char_traitsIcEEEEbEEE:
  397|  25.4k|    std::pair<unsigned int, void *> fenceAndConsumePostPadded(char *data, unsigned int length, void *user, void *reserved, HttpRequest *req, MoveOnlyFunction<void *(void *, HttpRequest *)> &requestHandler, MoveOnlyFunction<void *(void *, std::string_view, bool)> &dataHandler) {
  398|       |
  399|       |        /* How much data we CONSUMED (to throw away) */
  400|  25.4k|        unsigned int consumedTotal = 0;
  401|  25.4k|        unsigned int err = 0;
  402|       |
  403|       |        /* Fence two bytes past end of our buffer (buffer has post padded margins).
  404|       |         * This is to always catch scan for \r but not for \r\n. */
  405|  25.4k|        data[length] = '\r';
  406|  25.4k|        data[length + 1] = 'a'; /* Anything that is not \n, to trigger "invalid request" */
  407|       |
  408|  25.4k|        for (unsigned int consumed; length && (consumed = getHeaders(data, data + length, req->headers, reserved, err)); ) {
  ------------------
  |  Branch (408:37): [True: 25.4k, False: 0]
  |  Branch (408:47): [True: 10.5k, False: 14.8k]
  ------------------
  409|  10.5k|            data += consumed;
  410|  10.5k|            length -= consumed;
  411|  10.5k|            consumedTotal += consumed;
  412|       |
  413|       |            /* Store HTTP version (ancient 1.0 or 1.1) */
  414|  10.5k|            req->ancientHttp = false;
  415|       |
  416|       |            /* Add all headers to bloom filter */
  417|  10.5k|            req->bf.reset();
  418|  27.8k|            for (HttpRequest::Header *h = req->headers; (++h)->key.length(); ) {
  ------------------
  |  Branch (418:57): [True: 17.2k, False: 10.5k]
  ------------------
  419|  17.2k|                req->bf.add(h->key);
  420|  17.2k|            }
  421|       |            
  422|       |            /* Break if no host header (but we can have empty string which is different from nullptr) */
  423|  10.5k|            if (!req->getHeader("host").data()) {
  ------------------
  |  Branch (423:17): [True: 2.28k, False: 8.30k]
  ------------------
  424|  2.28k|                return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  425|  2.28k|            }
  426|       |
  427|       |            /* RFC 9112 6.3
  428|       |            * If a message is received with both a Transfer-Encoding and a Content-Length header field,
  429|       |            * the Transfer-Encoding overrides the Content-Length. Such a message might indicate an attempt
  430|       |            * to perform request smuggling (Section 11.2) or response splitting (Section 11.1) and
  431|       |            * ought to be handled as an error. */
  432|  8.30k|            std::string_view transferEncodingString = req->getHeader("transfer-encoding");
  433|  8.30k|            std::string_view contentLengthString = req->getHeader("content-length");
  434|  8.30k|            if (transferEncodingString.length() && contentLengthString.length()) {
  ------------------
  |  Branch (434:17): [True: 0, False: 8.30k]
  |  Branch (434:52): [True: 0, False: 0]
  ------------------
  435|       |                /* Returning fullptr is the same as calling the errorHandler */
  436|       |                /* We could be smart and set an error in the context along with this, to indicate what 
  437|       |                 * http error response we might want to return */
  438|      0|                return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  439|      0|            }
  440|       |
  441|       |            /* Parse query */
  442|  8.30k|            const char *querySeparatorPtr = (const char *) memchr(req->headers->value.data(), '?', req->headers->value.length());
  443|  8.30k|            req->querySeparator = (unsigned int) ((querySeparatorPtr ? querySeparatorPtr : req->headers->value.data() + req->headers->value.length()) - req->headers->value.data());
  ------------------
  |  Branch (443:52): [True: 349, False: 7.95k]
  ------------------
  444|       |
  445|       |            /* If returned socket is not what we put in we need
  446|       |             * to break here as we either have upgraded to
  447|       |             * WebSockets or otherwise closed the socket. */
  448|  8.30k|            void *returnedUser = requestHandler(user, req);
  449|  8.30k|            if (returnedUser != user) {
  ------------------
  |  Branch (449:17): [True: 849, False: 7.45k]
  ------------------
  450|       |                /* We are upgraded to WebSocket or otherwise broken */
  451|    849|                return {consumedTotal, returnedUser};
  452|    849|            }
  453|       |
  454|       |            /* The rules at play here according to RFC 9112 for requests are essentially:
  455|       |             * If both content-length and transfer-encoding then invalid message; must break.
  456|       |             * If has transfer-encoding then must be chunked regardless of value.
  457|       |             * If content-length then fixed length even if 0.
  458|       |             * If none of the above then fixed length is 0. */
  459|       |
  460|       |            /* RFC 9112 6.3
  461|       |             * If a message is received with both a Transfer-Encoding and a Content-Length header field,
  462|       |             * the Transfer-Encoding overrides the Content-Length. */
  463|  7.45k|            if (transferEncodingString.length()) {
  ------------------
  |  Branch (463:17): [True: 0, False: 7.45k]
  ------------------
  464|       |
  465|       |                /* If a proxy sent us the transfer-encoding header that 100% means it must be chunked or else the proxy is
  466|       |                 * not RFC 9112 compliant. Therefore it is always better to assume this is the case, since that entirely eliminates 
  467|       |                 * all forms of transfer-encoding obfuscation tricks. We just rely on the header. */
  468|       |
  469|       |                /* RFC 9112 6.3
  470|       |                 * If a Transfer-Encoding header field is present in a request and the chunked transfer coding is not the
  471|       |                 * final encoding, the message body length cannot be determined reliably; the server MUST respond with the
  472|       |                 * 400 (Bad Request) status code and then close the connection. */
  473|       |
  474|       |                /* In this case we fail later by having the wrong interpretation (assuming chunked).
  475|       |                 * This could be made stricter but makes no difference either way, unless forwarding the identical message as a proxy. */
  476|       |
  477|      0|                remainingStreamingBytes = STATE_IS_CHUNKED;
  478|       |                /* If consume minimally, we do not want to consume anything but we want to mark this as being chunked */
  479|      0|                if (!CONSUME_MINIMALLY) {
  ------------------
  |  Branch (479:21): [Folded - Ignored]
  ------------------
  480|       |                    /* Go ahead and parse it (todo: better heuristics for emitting FIN to the app level) */
  481|      0|                    std::string_view dataToConsume(data, length);
  482|      0|                    for (auto chunk : uWS::ChunkIterator(&dataToConsume, &remainingStreamingBytes)) {
  ------------------
  |  Branch (482:37): [True: 0, False: 0]
  ------------------
  483|      0|                        dataHandler(user, chunk, chunk.length() == 0);
  484|      0|                    }
  485|      0|                    if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) {
  ------------------
  |  Branch (485:25): [True: 0, False: 0]
  ------------------
  486|      0|                        return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  487|      0|                    }
  488|      0|                    unsigned int consumed = (length - (unsigned int) dataToConsume.length());
  489|      0|                    data = (char *) dataToConsume.data();
  490|      0|                    length = (unsigned int) dataToConsume.length();
  491|      0|                    consumedTotal += consumed;
  492|      0|                }
  493|  7.45k|            } else if (contentLengthString.length()) {
  ------------------
  |  Branch (493:24): [True: 0, False: 7.45k]
  ------------------
  494|      0|                remainingStreamingBytes = toUnsignedInteger(contentLengthString);
  495|      0|                if (remainingStreamingBytes == UINT_MAX) {
  ------------------
  |  Branch (495:21): [True: 0, False: 0]
  ------------------
  496|       |                    /* Parser error */
  497|      0|                    return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  498|      0|                }
  499|       |
  500|      0|                if (!CONSUME_MINIMALLY) {
  ------------------
  |  Branch (500:21): [Folded - Ignored]
  ------------------
  501|      0|                    unsigned int emittable = std::min<unsigned int>(remainingStreamingBytes, length);
  502|      0|                    dataHandler(user, std::string_view(data, emittable), emittable == remainingStreamingBytes);
  503|      0|                    remainingStreamingBytes -= emittable;
  504|       |
  505|      0|                    data += emittable;
  506|      0|                    length -= emittable;
  507|      0|                    consumedTotal += emittable;
  508|      0|                }
  509|  7.45k|            } else {
  510|       |                /* If we came here without a body; emit an empty data chunk to signal no data */
  511|  7.45k|                dataHandler(user, {}, true);
  512|  7.45k|            }
  513|       |
  514|       |            /* Consume minimally should break as easrly as possible */
  515|  7.45k|            if (CONSUME_MINIMALLY) {
  ------------------
  |  Branch (515:17): [Folded - Ignored]
  ------------------
  516|  7.45k|                break;
  517|  7.45k|            }
  518|  7.45k|        }
  519|       |        /* Whenever we return FULLPTR, the interpretation of "consumed" should be the HttpError enum. */
  520|  22.3k|        if (err) {
  ------------------
  |  Branch (520:13): [True: 0, False: 22.3k]
  ------------------
  521|      0|            return {err, FULLPTR};
  522|      0|        }
  523|  22.3k|        return {consumedTotal, user};
  524|  22.3k|    }
_ZN3uWS10HttpParser10getHeadersEPcS1_PNS_11HttpRequest6HeaderEPvRj:
  286|   147k|    static unsigned int getHeaders(char *postPaddedBuffer, char *end, struct HttpRequest::Header *headers, void *reserved, unsigned int &err) {
  287|   147k|        char *preliminaryKey, *preliminaryValue, *start = postPaddedBuffer;
  288|       |
  289|       |        #ifdef UWS_WITH_PROXY
  290|       |            /* ProxyParser is passed as reserved parameter */
  291|       |            ProxyParser *pp = (ProxyParser *) reserved;
  292|       |
  293|       |            /* Parse PROXY protocol */
  294|       |            auto [done, offset] = pp->parse({postPaddedBuffer, (size_t) (end - postPaddedBuffer)});
  295|       |            if (!done) {
  296|       |                /* We do not reset the ProxyParser (on filure) since it is tied to this
  297|       |                * connection, which is really only supposed to ever get one PROXY frame
  298|       |                * anyways. We do however allow multiple PROXY frames to be sent (overwrites former). */
  299|       |                return 0;
  300|       |            } else {
  301|       |                /* We have consumed this data so skip it */
  302|       |                postPaddedBuffer += offset;
  303|       |            }
  304|       |        #else
  305|       |            /* This one is unused */
  306|   147k|            (void) reserved;
  307|   147k|            (void) end;
  308|   147k|        #endif
  309|       |
  310|       |        /* It is critical for fallback buffering logic that we only return with success
  311|       |         * if we managed to parse a complete HTTP request (minus data). Returning success
  312|       |         * for PROXY means we can end up succeeding, yet leaving bytes in the fallback buffer
  313|       |         * which is then removed, and our counters to flip due to overflow and we end up with a crash */
  314|       |
  315|       |        /* The request line is different from the field names / field values */
  316|   147k|        if (!(postPaddedBuffer = consumeRequestLine(postPaddedBuffer, headers[0]))) {
  ------------------
  |  Branch (316:13): [True: 85.2k, False: 61.9k]
  ------------------
  317|       |            /* Error - invalid request line */
  318|       |            /* Assuming it is 505 HTTP Version Not Supported */
  319|  85.2k|            err = HTTP_ERROR_505_HTTP_VERSION_NOT_SUPPORTED;
  320|  85.2k|            return 0;
  321|  85.2k|        }
  322|  61.9k|        headers++;
  323|       |
  324|  86.3k|        for (unsigned int i = 1; i < HttpRequest::MAX_HEADERS - 1; i++) {
  ------------------
  |  Branch (324:34): [True: 86.1k, False: 194]
  ------------------
  325|       |            /* Lower case and consume the field name */
  326|  86.1k|            preliminaryKey = postPaddedBuffer;
  327|  86.1k|            postPaddedBuffer = (char *) consumeFieldName(postPaddedBuffer);
  328|  86.1k|            headers->key = std::string_view(preliminaryKey, (size_t) (postPaddedBuffer - preliminaryKey));
  329|       |
  330|       |            /* We should not accept whitespace between key and colon, so colon must foloow immediately */
  331|  86.1k|            if (postPaddedBuffer[0] != ':') {
  ------------------
  |  Branch (331:17): [True: 7.89k, False: 78.2k]
  ------------------
  332|       |                /* Error: invalid chars in field name */
  333|  7.89k|                return 0;
  334|  7.89k|            }
  335|  78.2k|            postPaddedBuffer++;
  336|       |
  337|  78.2k|            preliminaryValue = postPaddedBuffer;
  338|       |            /* The goal of this call is to find next "\r\n", or any invalid field value chars, fast */
  339|  78.5k|            while (true) {
  ------------------
  |  Branch (339:20): [Folded - Ignored]
  ------------------
  340|  78.5k|                postPaddedBuffer = (char *) tryConsumeFieldValue(postPaddedBuffer);
  341|       |                /* If this is not CR then we caught some stinky invalid char on the way */
  342|  78.5k|                if (postPaddedBuffer[0] != '\r') {
  ------------------
  |  Branch (342:21): [True: 2.04k, False: 76.4k]
  ------------------
  343|       |                    /* If TAB then keep searching */
  344|  2.04k|                    if (postPaddedBuffer[0] == '\t') {
  ------------------
  |  Branch (344:25): [True: 249, False: 1.79k]
  ------------------
  345|    249|                        postPaddedBuffer++;
  346|    249|                        continue;
  347|    249|                    }
  348|       |                    /* Error - invalid chars in field value */
  349|  1.79k|                    return 0;
  350|  2.04k|                }
  351|  76.4k|                break;
  352|  78.5k|            }
  353|       |            /* We fence end[0] with \r, followed by end[1] being something that is "not \n", to signify "not found".
  354|       |                * This way we can have this one single check to see if we found \r\n WITHIN our allowed search space. */
  355|  76.4k|            if (postPaddedBuffer[1] == '\n') {
  ------------------
  |  Branch (355:17): [True: 55.8k, False: 20.6k]
  ------------------
  356|       |                /* Store this header, it is valid */
  357|  55.8k|                headers->value = std::string_view(preliminaryValue, (size_t) (postPaddedBuffer - preliminaryValue));
  358|  55.8k|                postPaddedBuffer += 2;
  359|       |
  360|       |                /* Trim trailing whitespace (SP, HTAB) */
  361|   114k|                while (headers->value.length() && headers->value.back() < 33) {
  ------------------
  |  Branch (361:24): [True: 90.7k, False: 23.4k]
  |  Branch (361:51): [True: 58.3k, False: 32.4k]
  ------------------
  362|  58.3k|                    headers->value.remove_suffix(1);
  363|  58.3k|                }
  364|       |
  365|       |                /* Trim initial whitespace (SP, HTAB) */
  366|  76.7k|                while (headers->value.length() && headers->value.front() < 33) {
  ------------------
  |  Branch (366:24): [True: 53.2k, False: 23.4k]
  |  Branch (366:51): [True: 20.8k, False: 32.4k]
  ------------------
  367|  20.8k|                    headers->value.remove_prefix(1);
  368|  20.8k|                }
  369|       |                
  370|  55.8k|                headers++;
  371|       |
  372|       |                /* We definitely have at least one header (or request line), so check if we are done */
  373|  55.8k|                if (*postPaddedBuffer == '\r') {
  ------------------
  |  Branch (373:21): [True: 31.4k, False: 24.3k]
  ------------------
  374|  31.4k|                    if (postPaddedBuffer[1] == '\n') {
  ------------------
  |  Branch (374:25): [True: 30.6k, False: 775]
  ------------------
  375|       |                        /* This cann take the very last header space */
  376|  30.6k|                        headers->key = std::string_view(nullptr, 0);
  377|  30.6k|                        return (unsigned int) ((postPaddedBuffer + 2) - start);
  378|  30.6k|                    } else {
  379|       |                        /* \r\n\r plus non-\n letter is malformed request, or simply out of search space */
  380|    775|                        return 0;
  381|    775|                    }
  382|  31.4k|                }
  383|  55.8k|            } else {
  384|       |                /* We are either out of search space or this is a malformed request */
  385|  20.6k|                return 0;
  386|  20.6k|            }
  387|  76.4k|        }
  388|       |        /* We ran out of header space, too large request */
  389|    194|        return 0;
  390|  61.9k|    }
_ZN3uWS10HttpParser18consumeRequestLineEPcRNS_11HttpRequest6HeaderE:
  242|   147k|    static inline char *consumeRequestLine(char *data, HttpRequest::Header &header) {
  243|       |        /* Scan until single SP, assume next is / (origin request) */
  244|   147k|        char *start = data;
  245|       |        /* This catches the post padded CR and fails */
  246|   474k|        while (data[0] > 32) data++;
  ------------------
  |  Branch (246:16): [True: 326k, False: 147k]
  ------------------
  247|   147k|        if (data[0] == 32 && data[1] == '/') {
  ------------------
  |  Branch (247:13): [True: 72.9k, False: 74.3k]
  |  Branch (247:30): [True: 68.8k, False: 4.08k]
  ------------------
  248|  68.8k|            header.key = {start, (size_t) (data - start)};
  249|  68.8k|            data++;
  250|       |            /* Scan for less than 33 (catches post padded CR and fails) */
  251|  68.8k|            start = data;
  252|  70.9k|            for (; true; data += 8) {
  ------------------
  |  Branch (252:20): [Folded - Ignored]
  ------------------
  253|  70.9k|                uint64_t word;
  254|  70.9k|                memcpy(&word, data, sizeof(uint64_t));
  255|  70.9k|                if (hasLess(word, 33)) {
  ------------------
  |  Branch (255:21): [True: 68.8k, False: 2.11k]
  ------------------
  256|   257k|                    while (*(unsigned char *)data > 32) data++;
  ------------------
  |  Branch (256:28): [True: 188k, False: 68.8k]
  ------------------
  257|       |                    /* Now we stand on space */
  258|  68.8k|                    header.value = {start, (size_t) (data - start)};
  259|       |                    /* Check that the following is http 1.1 */
  260|  68.8k|                    if (memcmp(" HTTP/1.1\r\n", data, 11) == 0) {
  ------------------
  |  Branch (260:25): [True: 61.9k, False: 6.87k]
  ------------------
  261|  61.9k|                        return data + 11;
  262|  61.9k|                    }
  263|  6.87k|                    return nullptr;
  264|  68.8k|                }
  265|  70.9k|            }
  266|  68.8k|        }
  267|  78.3k|        return nullptr;
  268|   147k|    }
_ZN3uWS10HttpParser7hasLessEmm:
  206|   374k|    static inline uint64_t hasLess(uint64_t x, uint64_t n) {
  207|   374k|        return (((x)-~0ULL/255*(n))&~(x)&~0ULL/255*128);
  208|   374k|    }
_ZN3uWS10HttpParser16consumeFieldNameEPc:
  226|  86.1k|    static inline void *consumeFieldName(char *p) {
  227|   117k|        for (; true; p += 8) {
  ------------------
  |  Branch (227:16): [Folded - Ignored]
  ------------------
  228|   117k|            uint64_t word;
  229|   117k|            memcpy(&word, p, sizeof(uint64_t));
  230|   117k|            if (notFieldNameWord(word)) {
  ------------------
  |  Branch (230:17): [True: 86.1k, False: 31.4k]
  ------------------
  231|   332k|                while (isFieldNameByte(*(unsigned char *)p)) {
  ------------------
  |  Branch (231:24): [True: 246k, False: 86.1k]
  ------------------
  232|   246k|                    *(p++) |= 0x20;
  233|   246k|                }
  234|  86.1k|                return (void *)p;
  235|  86.1k|            }
  236|  31.4k|            word |= 0x2020202020202020ull;
  237|  31.4k|            memcpy(p, &word, sizeof(uint64_t));
  238|  31.4k|        }
  239|  86.1k|    }
_ZN3uWS10HttpParser16notFieldNameWordEm:
  218|   117k|    static inline bool notFieldNameWord(uint64_t x) {
  219|   117k|        return hasLess(x, '-') |
  220|   117k|        hasBetween(x, '-', '0') |
  221|   117k|        hasBetween(x, '9', 'A') |
  222|   117k|        hasBetween(x, 'Z', 'a') |
  223|   117k|        hasMore(x, 'z');
  224|   117k|    }
_ZN3uWS10HttpParser10hasBetweenEmmm:
  214|   352k|    static inline uint64_t hasBetween(uint64_t x, uint64_t m, uint64_t n) {
  215|   352k|        return (( (~0ULL/255*(127+(n))-((x)&~0ULL/255*127)) &~(x)& (((x)&~0ULL/255*127)+~0ULL/255*(127-(m))) )&~0ULL/255*128);
  216|   352k|    }
_ZN3uWS10HttpParser7hasMoreEmm:
  210|   117k|    static inline uint64_t hasMore(uint64_t x, uint64_t n) {
  211|   117k|        return (( ((x)+~0ULL/255*(127-(n))) |(x))&~0ULL/255*128);
  212|   117k|    }
_ZN3uWS10HttpParser15isFieldNameByteEh:
  199|   332k|    static inline bool isFieldNameByte(unsigned char x) {
  200|   332k|        return (x == '-') |
  201|   332k|        ((x > '/') & (x < ':')) |
  202|   332k|        ((x > '@') & (x < '[')) |
  203|   332k|        ((x > 96) & (x < '{'));
  204|   332k|    }
_ZN3uWS10HttpParser20tryConsumeFieldValueEPc:
  274|  78.5k|    static inline void *tryConsumeFieldValue(char *p) {
  275|   185k|        for (; true; p += 8) {
  ------------------
  |  Branch (275:16): [Folded - Ignored]
  ------------------
  276|   185k|            uint64_t word;
  277|   185k|            memcpy(&word, p, sizeof(uint64_t));
  278|   185k|            if (hasLess(word, 32)) {
  ------------------
  |  Branch (278:17): [True: 78.5k, False: 107k]
  ------------------
  279|   244k|                while (*(unsigned char *)p > 31) p++;
  ------------------
  |  Branch (279:24): [True: 165k, False: 78.5k]
  ------------------
  280|  78.5k|                return (void *)p;
  281|  78.5k|            }
  282|   185k|        }
  283|  78.5k|    }
_ZN3uWS11HttpRequest9getHeaderENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
  103|   134k|    std::string_view getHeader(std::string_view lowerCasedHeader) {
  104|   134k|        if (bf.mightHave(lowerCasedHeader)) {
  ------------------
  |  Branch (104:13): [True: 31.6k, False: 103k]
  ------------------
  105|  38.3k|            for (Header *h = headers; (++h)->key.length(); ) {
  ------------------
  |  Branch (105:39): [True: 37.9k, False: 403]
  ------------------
  106|  37.9k|                if (h->key.length() == lowerCasedHeader.length() && !strncmp(h->key.data(), lowerCasedHeader.data(), lowerCasedHeader.length())) {
  ------------------
  |  Branch (106:21): [True: 32.2k, False: 5.64k]
  |  Branch (106:69): [True: 31.2k, False: 975]
  ------------------
  107|  31.2k|                    return h->value;
  108|  31.2k|                }
  109|  37.9k|            }
  110|  31.6k|        }
  111|   103k|        return std::string_view(nullptr, 0);
  112|   134k|    }
_ZN3uWS10HttpParser25fenceAndConsumePostPaddedILi0EEENSt3__14pairIjPvEEPcjS4_S4_PNS_11HttpRequestERN5ofats13any_invocableIFS4_S4_S8_EEERNSA_IFS4_S4_NS2_17basic_string_viewIcNS2_11char_traitsIcEEEEbEEE:
  397|   114k|    std::pair<unsigned int, void *> fenceAndConsumePostPadded(char *data, unsigned int length, void *user, void *reserved, HttpRequest *req, MoveOnlyFunction<void *(void *, HttpRequest *)> &requestHandler, MoveOnlyFunction<void *(void *, std::string_view, bool)> &dataHandler) {
  398|       |
  399|       |        /* How much data we CONSUMED (to throw away) */
  400|   114k|        unsigned int consumedTotal = 0;
  401|   114k|        unsigned int err = 0;
  402|       |
  403|       |        /* Fence two bytes past end of our buffer (buffer has post padded margins).
  404|       |         * This is to always catch scan for \r but not for \r\n. */
  405|   114k|        data[length] = '\r';
  406|   114k|        data[length + 1] = 'a'; /* Anything that is not \n, to trigger "invalid request" */
  407|       |
  408|   130k|        for (unsigned int consumed; length && (consumed = getHeaders(data, data + length, req->headers, reserved, err)); ) {
  ------------------
  |  Branch (408:37): [True: 121k, False: 8.99k]
  |  Branch (408:47): [True: 20.0k, False: 101k]
  ------------------
  409|  20.0k|            data += consumed;
  410|  20.0k|            length -= consumed;
  411|  20.0k|            consumedTotal += consumed;
  412|       |
  413|       |            /* Store HTTP version (ancient 1.0 or 1.1) */
  414|  20.0k|            req->ancientHttp = false;
  415|       |
  416|       |            /* Add all headers to bloom filter */
  417|  20.0k|            req->bf.reset();
  418|  43.1k|            for (HttpRequest::Header *h = req->headers; (++h)->key.length(); ) {
  ------------------
  |  Branch (418:57): [True: 23.1k, False: 20.0k]
  ------------------
  419|  23.1k|                req->bf.add(h->key);
  420|  23.1k|            }
  421|       |            
  422|       |            /* Break if no host header (but we can have empty string which is different from nullptr) */
  423|  20.0k|            if (!req->getHeader("host").data()) {
  ------------------
  |  Branch (423:17): [True: 996, False: 19.0k]
  ------------------
  424|    996|                return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  425|    996|            }
  426|       |
  427|       |            /* RFC 9112 6.3
  428|       |            * If a message is received with both a Transfer-Encoding and a Content-Length header field,
  429|       |            * the Transfer-Encoding overrides the Content-Length. Such a message might indicate an attempt
  430|       |            * to perform request smuggling (Section 11.2) or response splitting (Section 11.1) and
  431|       |            * ought to be handled as an error. */
  432|  19.0k|            std::string_view transferEncodingString = req->getHeader("transfer-encoding");
  433|  19.0k|            std::string_view contentLengthString = req->getHeader("content-length");
  434|  19.0k|            if (transferEncodingString.length() && contentLengthString.length()) {
  ------------------
  |  Branch (434:17): [True: 0, False: 19.0k]
  |  Branch (434:52): [True: 0, False: 0]
  ------------------
  435|       |                /* Returning fullptr is the same as calling the errorHandler */
  436|       |                /* We could be smart and set an error in the context along with this, to indicate what 
  437|       |                 * http error response we might want to return */
  438|      0|                return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  439|      0|            }
  440|       |
  441|       |            /* Parse query */
  442|  19.0k|            const char *querySeparatorPtr = (const char *) memchr(req->headers->value.data(), '?', req->headers->value.length());
  443|  19.0k|            req->querySeparator = (unsigned int) ((querySeparatorPtr ? querySeparatorPtr : req->headers->value.data() + req->headers->value.length()) - req->headers->value.data());
  ------------------
  |  Branch (443:52): [True: 8.19k, False: 10.9k]
  ------------------
  444|       |
  445|       |            /* If returned socket is not what we put in we need
  446|       |             * to break here as we either have upgraded to
  447|       |             * WebSockets or otherwise closed the socket. */
  448|  19.0k|            void *returnedUser = requestHandler(user, req);
  449|  19.0k|            if (returnedUser != user) {
  ------------------
  |  Branch (449:17): [True: 3.30k, False: 15.7k]
  ------------------
  450|       |                /* We are upgraded to WebSocket or otherwise broken */
  451|  3.30k|                return {consumedTotal, returnedUser};
  452|  3.30k|            }
  453|       |
  454|       |            /* The rules at play here according to RFC 9112 for requests are essentially:
  455|       |             * If both content-length and transfer-encoding then invalid message; must break.
  456|       |             * If has transfer-encoding then must be chunked regardless of value.
  457|       |             * If content-length then fixed length even if 0.
  458|       |             * If none of the above then fixed length is 0. */
  459|       |
  460|       |            /* RFC 9112 6.3
  461|       |             * If a message is received with both a Transfer-Encoding and a Content-Length header field,
  462|       |             * the Transfer-Encoding overrides the Content-Length. */
  463|  15.7k|            if (transferEncodingString.length()) {
  ------------------
  |  Branch (463:17): [True: 0, False: 15.7k]
  ------------------
  464|       |
  465|       |                /* If a proxy sent us the transfer-encoding header that 100% means it must be chunked or else the proxy is
  466|       |                 * not RFC 9112 compliant. Therefore it is always better to assume this is the case, since that entirely eliminates 
  467|       |                 * all forms of transfer-encoding obfuscation tricks. We just rely on the header. */
  468|       |
  469|       |                /* RFC 9112 6.3
  470|       |                 * If a Transfer-Encoding header field is present in a request and the chunked transfer coding is not the
  471|       |                 * final encoding, the message body length cannot be determined reliably; the server MUST respond with the
  472|       |                 * 400 (Bad Request) status code and then close the connection. */
  473|       |
  474|       |                /* In this case we fail later by having the wrong interpretation (assuming chunked).
  475|       |                 * This could be made stricter but makes no difference either way, unless forwarding the identical message as a proxy. */
  476|       |
  477|      0|                remainingStreamingBytes = STATE_IS_CHUNKED;
  478|       |                /* If consume minimally, we do not want to consume anything but we want to mark this as being chunked */
  479|      0|                if (!CONSUME_MINIMALLY) {
  ------------------
  |  Branch (479:21): [Folded - Ignored]
  ------------------
  480|       |                    /* Go ahead and parse it (todo: better heuristics for emitting FIN to the app level) */
  481|      0|                    std::string_view dataToConsume(data, length);
  482|      0|                    for (auto chunk : uWS::ChunkIterator(&dataToConsume, &remainingStreamingBytes)) {
  ------------------
  |  Branch (482:37): [True: 0, False: 0]
  ------------------
  483|      0|                        dataHandler(user, chunk, chunk.length() == 0);
  484|      0|                    }
  485|      0|                    if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) {
  ------------------
  |  Branch (485:25): [True: 0, False: 0]
  ------------------
  486|      0|                        return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  487|      0|                    }
  488|      0|                    unsigned int consumed = (length - (unsigned int) dataToConsume.length());
  489|      0|                    data = (char *) dataToConsume.data();
  490|      0|                    length = (unsigned int) dataToConsume.length();
  491|      0|                    consumedTotal += consumed;
  492|      0|                }
  493|  15.7k|            } else if (contentLengthString.length()) {
  ------------------
  |  Branch (493:24): [True: 0, False: 15.7k]
  ------------------
  494|      0|                remainingStreamingBytes = toUnsignedInteger(contentLengthString);
  495|      0|                if (remainingStreamingBytes == UINT_MAX) {
  ------------------
  |  Branch (495:21): [True: 0, False: 0]
  ------------------
  496|       |                    /* Parser error */
  497|      0|                    return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  498|      0|                }
  499|       |
  500|      0|                if (!CONSUME_MINIMALLY) {
  ------------------
  |  Branch (500:21): [Folded - Ignored]
  ------------------
  501|      0|                    unsigned int emittable = std::min<unsigned int>(remainingStreamingBytes, length);
  502|      0|                    dataHandler(user, std::string_view(data, emittable), emittable == remainingStreamingBytes);
  503|      0|                    remainingStreamingBytes -= emittable;
  504|       |
  505|      0|                    data += emittable;
  506|      0|                    length -= emittable;
  507|      0|                    consumedTotal += emittable;
  508|      0|                }
  509|  15.7k|            } else {
  510|       |                /* If we came here without a body; emit an empty data chunk to signal no data */
  511|  15.7k|                dataHandler(user, {}, true);
  512|  15.7k|            }
  513|       |
  514|       |            /* Consume minimally should break as easrly as possible */
  515|  15.7k|            if (CONSUME_MINIMALLY) {
  ------------------
  |  Branch (515:17): [Folded - Ignored]
  ------------------
  516|      0|                break;
  517|      0|            }
  518|  15.7k|        }
  519|       |        /* Whenever we return FULLPTR, the interpretation of "consumed" should be the HttpError enum. */
  520|   110k|        if (err) {
  ------------------
  |  Branch (520:13): [True: 85.2k, False: 25.4k]
  ------------------
  521|  85.2k|            return {err, FULLPTR};
  522|  85.2k|        }
  523|  25.4k|        return {consumedTotal, user};
  524|   110k|    }
_ZN3uWS11HttpRequest9isAncientEv:
   60|  26.1k|    bool isAncient() {
   61|  26.1k|        return ancientHttp;
   62|  26.1k|    }
_ZN3uWS11HttpRequest22getCaseSensitiveMethodEv:
  123|  26.1k|    std::string_view getCaseSensitiveMethod() {
  124|  26.1k|        return std::string_view(headers->key.data(), headers->key.length());
  125|  26.1k|    }
_ZN3uWS11HttpRequest6getUrlEv:
  114|  26.1k|    std::string_view getUrl() {
  115|  26.1k|        return std::string_view(headers->value.data(), querySeparator);
  116|  26.1k|    }
_ZN3uWS11HttpRequest8setYieldEb:
   99|  23.2k|    void setYield(bool yield) {
  100|  23.2k|        didYield = yield;
  101|  23.2k|    }
_ZN3uWS11HttpRequest13setParametersENSt3__14pairIiPNS1_17basic_string_viewIcNS1_11char_traitsIcEEEEEE:
  154|  23.2k|    void setParameters(std::pair<int, std::string_view *> parameters) {
  155|  23.2k|        currentParameters = parameters;
  156|  23.2k|    }
_ZN3uWS11HttpRequest8getYieldEv:
   64|  23.2k|    bool getYield() {
   65|  23.2k|        return didYield;
   66|  23.2k|    }

_ZN3uWS12HttpResponseILb0EE12hasRespondedEv:
  490|  46.4k|    bool hasResponded() {
  491|  46.4k|        HttpResponseData<SSL> *httpResponseData = getHttpResponseData();
  492|       |
  493|  46.4k|        return !(httpResponseData->state & HttpResponseData<SSL>::HTTP_RESPONSE_PENDING);
  494|  46.4k|    }
_ZN3uWS12HttpResponseILb0EE19getHttpResponseDataEv:
   52|   135k|    HttpResponseData<SSL> *getHttpResponseData() {
   53|   135k|        return (HttpResponseData<SSL> *) Super::getAsyncSocketData();
   54|   135k|    }
_ZN3uWS12HttpResponseILb0EE9onAbortedEON5ofats13any_invocableIFvvEEE:
  558|  23.2k|    HttpResponse *onAborted(MoveOnlyFunction<void()> &&handler) {
  559|  23.2k|        HttpResponseData<SSL> *httpResponseData = getHttpResponseData();
  560|       |
  561|  23.2k|        httpResponseData->onAborted = std::move(handler);
  562|  23.2k|        return this;
  563|  23.2k|    }
_ZN3uWS12HttpResponseILb0EE4corkEON5ofats13any_invocableIFvvEEE:
  497|  13.0k|    HttpResponse *cork(MoveOnlyFunction<void()> &&handler) {
  498|  13.0k|        if (!Super::isCorked() && Super::canCork()) {
  ------------------
  |  Branch (498:13): [True: 13.0k, False: 0]
  |  Branch (498:35): [True: 13.0k, False: 0]
  ------------------
  499|  13.0k|            Super::cork();
  500|  13.0k|            handler();
  501|       |
  502|       |            /* The only way we could possibly have changed the corked socket during handler call, would be if 
  503|       |             * the HTTP socket was upgraded to WebSocket and caused a realloc. Because of this we cannot use "this"
  504|       |             * from here downwards. The corking is done with corkUnchecked() in upgrade. It steals cork. */
  505|  13.0k|            auto *newCorkedSocket = Super::corkedSocket();
  506|       |
  507|       |            /* If nobody is corked, it means most probably that large amounts of data has
  508|       |             * been written and the cork buffer has already been sent off and uncorked.
  509|       |             * We are done here, if that is the case. */
  510|  13.0k|            if (!newCorkedSocket) {
  ------------------
  |  Branch (510:17): [True: 0, False: 13.0k]
  ------------------
  511|      0|                return this;
  512|      0|            }
  513|       |
  514|       |            /* Timeout on uncork failure, since most writes will succeed while corked */
  515|  13.0k|            auto [written, failed] = static_cast<Super *>(newCorkedSocket)->uncork();
  516|       |
  517|       |            /* If we are no longer an HTTP socket then early return the new "this".
  518|       |             * We don't want to even overwrite timeout as it is set in upgrade already. */
  519|  13.0k|            if (this != newCorkedSocket) {
  ------------------
  |  Branch (519:17): [True: 0, False: 13.0k]
  ------------------
  520|      0|                return static_cast<HttpResponse *>(newCorkedSocket);
  521|      0|            }
  522|       |
  523|  13.0k|            if (failed) {
  ------------------
  |  Branch (523:17): [True: 11.5k, False: 1.52k]
  ------------------
  524|       |                /* For now we only have one single timeout so let's use it */
  525|       |                /* This behavior should equal the behavior in HttpContext when uncorking fails */
  526|  11.5k|                Super::timeout(HTTP_TIMEOUT_S);
  527|  11.5k|            }
  528|       |
  529|       |            /* If we have no backbuffer and we are connection close and we responded fully then close */
  530|  13.0k|            HttpResponseData<SSL> *httpResponseData = getHttpResponseData();
  531|  13.0k|            if (httpResponseData->state & HttpResponseData<SSL>::HTTP_CONNECTION_CLOSE) {
  ------------------
  |  Branch (531:17): [True: 2.55k, False: 10.5k]
  ------------------
  532|  2.55k|                if ((httpResponseData->state & HttpResponseData<SSL>::HTTP_RESPONSE_PENDING) == 0) {
  ------------------
  |  Branch (532:21): [True: 2.55k, False: 0]
  ------------------
  533|  2.55k|                    if (((AsyncSocket<SSL> *) this)->getBufferedAmount() == 0) {
  ------------------
  |  Branch (533:25): [True: 329, False: 2.22k]
  ------------------
  534|    329|                        ((AsyncSocket<SSL> *) this)->shutdown();
  535|       |                        /* We need to force close after sending FIN since we want to hinder
  536|       |                        * clients from keeping to send their huge data */
  537|    329|                        ((AsyncSocket<SSL> *) this)->close();
  538|    329|                    }
  539|  2.55k|                }
  540|  2.55k|            }
  541|  13.0k|        } else {
  542|       |            /* We are already corked, or can't cork so let's just call the handler */
  543|      0|            handler();
  544|      0|        }
  545|       |
  546|  13.0k|        return this;
  547|  13.0k|    }
_ZN3uWS12HttpResponseILb0EE3endENSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEb:
  432|  13.0k|    void end(std::string_view data = {}, bool closeConnection = false) {
  433|  13.0k|        internalEnd(data, data.length(), false, true, closeConnection);
  434|  13.0k|    }
_ZN3uWS12HttpResponseILb0EE11internalEndENSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEmbbb:
   92|  13.0k|    bool internalEnd(std::string_view data, uintmax_t totalSize, bool optional, bool allowContentLength = true, bool closeConnection = false) {
   93|       |        /* Write status if not already done */
   94|  13.0k|        writeStatus(HTTP_200_OK);
   95|       |
   96|       |        /* If no total size given then assume this chunk is everything */
   97|  13.0k|        if (!totalSize) {
  ------------------
  |  Branch (97:13): [True: 0, False: 13.0k]
  ------------------
   98|      0|            totalSize = data.length();
   99|      0|        }
  100|       |
  101|  13.0k|        HttpResponseData<SSL> *httpResponseData = getHttpResponseData();
  102|       |
  103|       |        /* In some cases, such as when refusing huge data we want to close the connection when drained */
  104|  13.0k|        if (closeConnection) {
  ------------------
  |  Branch (104:13): [True: 0, False: 13.0k]
  ------------------
  105|       |
  106|       |            /* HTTP 1.1 must send this back unless the client already sent it to us.
  107|       |             * It is a connection close when either of the two parties say so but the
  108|       |             * one party must tell the other one so.
  109|       |             *
  110|       |             * This check also serves to limit writing the header only once. */
  111|      0|            if ((httpResponseData->state & HttpResponseData<SSL>::HTTP_CONNECTION_CLOSE) == 0) {
  ------------------
  |  Branch (111:17): [True: 0, False: 0]
  ------------------
  112|      0|                writeHeader("Connection", "close");
  113|      0|            }
  114|       |
  115|      0|            httpResponseData->state |= HttpResponseData<SSL>::HTTP_CONNECTION_CLOSE;
  116|      0|        }
  117|       |
  118|  13.0k|        if (httpResponseData->state & HttpResponseData<SSL>::HTTP_WRITE_CALLED) {
  ------------------
  |  Branch (118:13): [True: 0, False: 13.0k]
  ------------------
  119|       |
  120|       |            /* We do not have tryWrite-like functionalities, so ignore optional in this path */
  121|       |
  122|       |            /* Do not allow sending 0 chunk here */
  123|      0|            if (data.length()) {
  ------------------
  |  Branch (123:17): [True: 0, False: 0]
  ------------------
  124|      0|                Super::write("\r\n", 2);
  125|      0|                writeUnsignedHex((unsigned int) data.length());
  126|      0|                Super::write("\r\n", 2);
  127|       |
  128|       |                /* Ignoring optional for now */
  129|      0|                Super::write(data.data(), (int) data.length());
  130|      0|            }
  131|       |
  132|       |            /* Terminating 0 chunk */
  133|      0|            Super::write("\r\n0\r\n\r\n", 7);
  134|       |
  135|      0|            httpResponseData->markDone();
  136|       |
  137|       |            /* We need to check if we should close this socket here now */
  138|      0|            if (!Super::isCorked()) {
  ------------------
  |  Branch (138:17): [True: 0, False: 0]
  ------------------
  139|      0|                if (httpResponseData->state & HttpResponseData<SSL>::HTTP_CONNECTION_CLOSE) {
  ------------------
  |  Branch (139:21): [True: 0, False: 0]
  ------------------
  140|      0|                    if ((httpResponseData->state & HttpResponseData<SSL>::HTTP_RESPONSE_PENDING) == 0) {
  ------------------
  |  Branch (140:25): [True: 0, False: 0]
  ------------------
  141|      0|                        if (((AsyncSocket<SSL> *) this)->getBufferedAmount() == 0) {
  ------------------
  |  Branch (141:29): [True: 0, False: 0]
  ------------------
  142|      0|                            ((AsyncSocket<SSL> *) this)->shutdown();
  143|       |                            /* We need to force close after sending FIN since we want to hinder
  144|       |                                * clients from keeping to send their huge data */
  145|      0|                            ((AsyncSocket<SSL> *) this)->close();
  146|      0|                            return true;
  147|      0|                        }
  148|      0|                    }
  149|      0|                }
  150|      0|            }
  151|       |
  152|       |            /* tryEnd can never fail when in chunked mode, since we do not have tryWrite (yet), only write */
  153|      0|            Super::timeout(HTTP_TIMEOUT_S);
  154|      0|            return true;
  155|  13.0k|        } else {
  156|       |            /* Write content-length on first call */
  157|  13.0k|            if (!(httpResponseData->state & HttpResponseData<SSL>::HTTP_END_CALLED)) {
  ------------------
  |  Branch (157:17): [True: 13.0k, False: 0]
  ------------------
  158|       |                /* Write mark, this propagates to WebSockets too */
  159|  13.0k|                writeMark();
  160|       |
  161|       |                /* WebSocket upgrades does not allow content-length */
  162|  13.0k|                if (allowContentLength) {
  ------------------
  |  Branch (162:21): [True: 13.0k, False: 0]
  ------------------
  163|       |                    /* Even zero is a valid content-length */
  164|  13.0k|                    Super::write("Content-Length: ", 16);
  165|  13.0k|                    writeUnsigned64(totalSize);
  166|  13.0k|                    Super::write("\r\n\r\n", 4);
  167|  13.0k|                } else {
  168|      0|                    Super::write("\r\n", 2);
  169|      0|                }
  170|       |
  171|       |                /* Mark end called */
  172|  13.0k|                httpResponseData->state |= HttpResponseData<SSL>::HTTP_END_CALLED;
  173|  13.0k|            }
  174|       |
  175|       |            /* Even if we supply no new data to write, its failed boolean is useful to know
  176|       |             * if it failed to drain any prior failed header writes */
  177|       |
  178|       |            /* Write as much as possible without causing backpressure */
  179|  13.0k|            size_t written = 0;
  180|  13.0k|            bool failed = false;
  181|  26.1k|            while (written < data.length() && !failed) {
  ------------------
  |  Branch (181:20): [True: 13.0k, False: 13.0k]
  |  Branch (181:47): [True: 13.0k, False: 0]
  ------------------
  182|       |                /* uSockets only deals with int sizes, so pass chunks of max signed int size */
  183|  13.0k|                auto writtenFailed = Super::write(data.data() + written, (int) std::min<size_t>(data.length() - written, INT_MAX), optional);
  184|       |
  185|  13.0k|                written += (size_t) writtenFailed.first;
  186|  13.0k|                failed = writtenFailed.second;
  187|  13.0k|            }
  188|       |
  189|  13.0k|            httpResponseData->offset += written;
  190|       |
  191|       |            /* Success is when we wrote the entire thing without any failures */
  192|  13.0k|            bool success = written == data.length() && !failed;
  ------------------
  |  Branch (192:28): [True: 13.0k, False: 0]
  |  Branch (192:56): [True: 12.6k, False: 465]
  ------------------
  193|       |
  194|       |            /* If we are now at the end, start a timeout. Also start a timeout if we failed. */
  195|  13.0k|            if (!success || httpResponseData->offset == totalSize) {
  ------------------
  |  Branch (195:17): [True: 465, False: 12.6k]
  |  Branch (195:29): [True: 12.6k, False: 0]
  ------------------
  196|  13.0k|                Super::timeout(HTTP_TIMEOUT_S);
  197|  13.0k|            }
  198|       |
  199|       |            /* Remove onAborted function if we reach the end */
  200|  13.0k|            if (httpResponseData->offset == totalSize) {
  ------------------
  |  Branch (200:17): [True: 13.0k, False: 0]
  ------------------
  201|  13.0k|                httpResponseData->markDone();
  202|       |
  203|       |                /* We need to check if we should close this socket here now */
  204|  13.0k|                if (!Super::isCorked()) {
  ------------------
  |  Branch (204:21): [True: 0, False: 13.0k]
  ------------------
  205|      0|                    if (httpResponseData->state & HttpResponseData<SSL>::HTTP_CONNECTION_CLOSE) {
  ------------------
  |  Branch (205:25): [True: 0, False: 0]
  ------------------
  206|      0|                        if ((httpResponseData->state & HttpResponseData<SSL>::HTTP_RESPONSE_PENDING) == 0) {
  ------------------
  |  Branch (206:29): [True: 0, False: 0]
  ------------------
  207|      0|                            if (((AsyncSocket<SSL> *) this)->getBufferedAmount() == 0) {
  ------------------
  |  Branch (207:33): [True: 0, False: 0]
  ------------------
  208|      0|                                ((AsyncSocket<SSL> *) this)->shutdown();
  209|       |                                /* We need to force close after sending FIN since we want to hinder
  210|       |                                * clients from keeping to send their huge data */
  211|      0|                                ((AsyncSocket<SSL> *) this)->close();
  212|      0|                            }
  213|      0|                        }
  214|      0|                    }
  215|      0|                }
  216|  13.0k|            }
  217|       |
  218|  13.0k|            return success;
  219|  13.0k|        }
  220|  13.0k|    }
_ZN3uWS12HttpResponseILb0EE11writeStatusENSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE:
  383|  39.2k|    HttpResponse *writeStatus(std::string_view status) {
  384|  39.2k|        HttpResponseData<SSL> *httpResponseData = getHttpResponseData();
  385|       |
  386|       |        /* Do not allow writing more than one status */
  387|  39.2k|        if (httpResponseData->state & HttpResponseData<SSL>::HTTP_STATUS_CALLED) {
  ------------------
  |  Branch (387:13): [True: 26.1k, False: 13.0k]
  ------------------
  388|  26.1k|            return this;
  389|  26.1k|        }
  390|       |
  391|       |        /* Update status */
  392|  13.0k|        httpResponseData->state |= HttpResponseData<SSL>::HTTP_STATUS_CALLED;
  393|       |
  394|  13.0k|        Super::write("HTTP/1.1 ", 9);
  395|  13.0k|        Super::write(status.data(), (int) status.length());
  396|  13.0k|        Super::write("\r\n", 2);
  397|  13.0k|        return this;
  398|  39.2k|    }
_ZN3uWS12HttpResponseILb0EE11writeHeaderENSt3__117basic_string_viewIcNS2_11char_traitsIcEEEES6_:
  401|  26.1k|    HttpResponse *writeHeader(std::string_view key, std::string_view value) {
  402|  26.1k|        writeStatus(HTTP_200_OK);
  403|       |
  404|  26.1k|        Super::write(key.data(), (int) key.length());
  405|  26.1k|        Super::write(": ", 2);
  406|  26.1k|        Super::write(value.data(), (int) value.length());
  407|  26.1k|        Super::write("\r\n", 2);
  408|  26.1k|        return this;
  409|  26.1k|    }
_ZN3uWS12HttpResponseILb0EE9writeMarkEv:
   77|  13.0k|    void writeMark() {
   78|       |        /* Date is always written */
   79|  13.0k|        writeHeader("Date", std::string_view(((LoopData *) us_loop_ext(us_socket_context_loop(SSL, (us_socket_context(SSL, (us_socket_t *) this)))))->date, 29));
   80|       |
   81|       |        /* You can disable this altogether */
   82|  13.0k|#ifndef UWS_HTTPRESPONSE_NO_WRITEMARK
   83|  13.0k|        if (!Super::getLoopData()->noMark) {
  ------------------
  |  Branch (83:13): [True: 13.0k, False: 0]
  ------------------
   84|       |            /* We only expose major version */
   85|  13.0k|            writeHeader("uWebSockets", "20");
   86|  13.0k|        }
   87|  13.0k|#endif
   88|  13.0k|    }
_ZN3uWS12HttpResponseILb0EE15writeUnsigned64Em:
   68|  13.0k|    void writeUnsigned64(uint64_t value) {
   69|  13.0k|        char buf[20];
   70|  13.0k|        int length = utils::u64toa(value, buf);
   71|       |
   72|       |        /* For now we do this copy */
   73|  13.0k|        Super::write(buf, length);
   74|  13.0k|    }

_ZN3uWS16HttpResponseDataILb0EE8markDoneEv:
   37|  13.0k|    void markDone() {
   38|  13.0k|        onAborted = nullptr;
   39|       |        /* Also remove onWritable so that we do not emit when draining behind the scenes. */
   40|  13.0k|        onWritable = nullptr;
   41|       |
   42|       |        /* We are done with this request */
   43|  13.0k|        state &= ~HttpResponseData<SSL>::HTTP_RESPONSE_PENDING;
   44|  13.0k|    }

_ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEEC2Ev:
  247|  1.65k|    HttpRouter() {
  248|  1.65k|        int p = 0;
  249|  14.8k|        for (std::string &method : upperCasedMethods) {
  ------------------
  |  Branch (249:34): [True: 14.8k, False: 1.65k]
  ------------------
  250|  14.8k|            priority[method] = p++;
  251|  14.8k|        }
  252|  1.65k|    }
_ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE4NodeC2ENSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEE:
   67|  4.96k|        Node(std::string name) : name(name) {}
_ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE11getUserDataEv:
  258|  49.4k|    USERDATA &getUserData() {
  259|  49.4k|        return userData;
  260|  49.4k|    }
_ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE5routeENSt3__117basic_string_viewIcNS5_11char_traitsIcEEEES9_:
  263|  26.1k|    bool route(std::string_view method, std::string_view url) {
  264|       |        /* Reset url parsing cache */
  265|  26.1k|        setUrl(url);
  266|  26.1k|        routeParameters.reset();
  267|       |
  268|       |        /* Begin by finding the method node */
  269|  26.1k|        for (auto &p : root.children) {
  ------------------
  |  Branch (269:22): [True: 26.1k, False: 2.93k]
  ------------------
  270|  26.1k|            if (p->name == method) {
  ------------------
  |  Branch (270:17): [True: 23.2k, False: 2.93k]
  ------------------
  271|       |                /* Then route the url */
  272|  23.2k|                return executeHandlers(p.get(), 0, userData);
  273|  23.2k|            }
  274|  26.1k|        }
  275|       |
  276|       |        /* We did not find any handler for this method and url */
  277|  2.93k|        return false;
  278|  26.1k|    }
_ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE6setUrlENSt3__117basic_string_viewIcNS5_11char_traitsIcEEEE:
  128|  29.4k|    inline void setUrl(std::string_view url) {
  129|       |
  130|       |        /* Todo: URL may also start with "http://domain/" or "*", not only "/" */
  131|       |
  132|       |        /* We expect to stand on a slash */
  133|  29.4k|        currentUrl = url;
  134|  29.4k|        urlSegmentTop = -1;
  135|  29.4k|    }
_ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE15RouteParameters5resetEv:
  112|  26.1k|        void reset() {
  113|  26.1k|            paramsTop = -1;
  114|  26.1k|        }
_ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE15executeHandlersEPNS4_4NodeEiRS3_:
  172|  23.2k|    bool executeHandlers(Node *parent, int urlSegment, USERDATA &userData) {
  173|       |
  174|  23.2k|        auto [segment, isStop] = getUrlSegment(urlSegment);
  175|       |
  176|       |        /* If we are on STOP, return where we may stand */
  177|  23.2k|        if (isStop) {
  ------------------
  |  Branch (177:13): [True: 0, False: 23.2k]
  ------------------
  178|       |            /* We have reached accross the entire URL with no stoppage, execute */
  179|      0|            for (uint32_t handler : parent->handlers) {
  ------------------
  |  Branch (179:35): [True: 0, False: 0]
  ------------------
  180|      0|                if (handlers[handler & HANDLER_MASK](this)) {
  ------------------
  |  Branch (180:21): [True: 0, False: 0]
  ------------------
  181|      0|                    return true;
  182|      0|                }
  183|      0|            }
  184|       |            /* We reached the end, so go back */
  185|      0|            return false;
  186|      0|        }
  187|       |
  188|  23.2k|        for (auto &p : parent->children) {
  ------------------
  |  Branch (188:22): [True: 23.2k, False: 0]
  ------------------
  189|  23.2k|            if (p->name.length() && p->name[0] == '*') {
  ------------------
  |  Branch (189:17): [True: 23.2k, False: 0]
  |  Branch (189:37): [True: 23.2k, False: 0]
  ------------------
  190|       |                /* Wildcard match (can be seen as a shortcut) */
  191|  23.2k|                for (uint32_t handler : p->handlers) {
  ------------------
  |  Branch (191:39): [True: 23.2k, False: 0]
  ------------------
  192|  23.2k|                    if (handlers[handler & HANDLER_MASK](this)) {
  ------------------
  |  Branch (192:25): [True: 23.2k, False: 0]
  ------------------
  193|  23.2k|                        return true;
  194|  23.2k|                    }
  195|  23.2k|                }
  196|  23.2k|            } else if (p->name.length() && p->name[0] == ':' && segment.length()) {
  ------------------
  |  Branch (196:24): [True: 0, False: 0]
  |  Branch (196:44): [True: 0, False: 0]
  |  Branch (196:65): [True: 0, False: 0]
  ------------------
  197|       |                /* Parameter match */
  198|      0|                routeParameters.push(segment);
  199|      0|                if (executeHandlers(p.get(), urlSegment + 1, userData)) {
  ------------------
  |  Branch (199:21): [True: 0, False: 0]
  ------------------
  200|      0|                    return true;
  201|      0|                }
  202|      0|                routeParameters.pop();
  203|      0|            } else if (p->name == segment) {
  ------------------
  |  Branch (203:24): [True: 0, False: 0]
  ------------------
  204|       |                /* Static match */
  205|      0|                if (executeHandlers(p.get(), urlSegment + 1, userData)) {
  ------------------
  |  Branch (205:21): [True: 0, False: 0]
  ------------------
  206|      0|                    return true;
  207|      0|                }
  208|      0|            }
  209|  23.2k|        }
  210|      0|        return false;
  211|  23.2k|    }
_ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE13getUrlSegmentEi:
  138|  33.1k|    inline std::pair<std::string_view, bool> getUrlSegment(int urlSegment) {
  139|  33.1k|        if (urlSegment > urlSegmentTop) {
  ------------------
  |  Branch (139:13): [True: 29.8k, False: 3.31k]
  ------------------
  140|       |            /* Signal as STOP when we have no more URL or stack space */
  141|  29.8k|            if (!currentUrl.length() || urlSegment > 99) {
  ------------------
  |  Branch (141:17): [True: 3.31k, False: 26.5k]
  |  Branch (141:41): [True: 0, False: 26.5k]
  ------------------
  142|  3.31k|                return {{}, true};
  143|  3.31k|            }
  144|       |
  145|       |            /* We always stand on a slash here, so step over it */
  146|  26.5k|            currentUrl.remove_prefix(1);
  147|       |
  148|  26.5k|            auto segmentLength = currentUrl.find('/');
  149|  26.5k|            if (segmentLength == std::string::npos) {
  ------------------
  |  Branch (149:17): [True: 21.4k, False: 5.15k]
  ------------------
  150|  21.4k|                segmentLength = currentUrl.length();
  151|       |
  152|       |                /* Push to url segment vector */
  153|  21.4k|                urlSegmentVector[urlSegment] = currentUrl.substr(0, segmentLength);
  154|  21.4k|                urlSegmentTop++;
  155|       |
  156|       |                /* Update currentUrl */
  157|  21.4k|                currentUrl = currentUrl.substr(segmentLength);
  158|  21.4k|            } else {
  159|       |                /* Push to url segment vector */
  160|  5.15k|                urlSegmentVector[urlSegment] = currentUrl.substr(0, segmentLength);
  161|  5.15k|                urlSegmentTop++;
  162|       |
  163|       |                /* Update currentUrl */
  164|  5.15k|                currentUrl = currentUrl.substr(segmentLength);
  165|  5.15k|            }
  166|  26.5k|        }
  167|       |        /* In any case we return it */
  168|  29.8k|        return {urlSegmentVector[urlSegment], false};
  169|  33.1k|    }
_ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE11findHandlerENSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEESB_j:
  214|  1.65k|    uint32_t findHandler(std::string method, std::string pattern, uint32_t priority) {
  215|  1.65k|        for (std::unique_ptr<Node> &node : root.children) {
  ------------------
  |  Branch (215:42): [True: 1.65k, False: 0]
  ------------------
  216|  1.65k|            if (method == node->name) {
  ------------------
  |  Branch (216:17): [True: 1.65k, False: 0]
  ------------------
  217|  1.65k|                setUrl(pattern);
  218|  1.65k|                Node *n = node.get();
  219|  3.31k|                for (int i = 0; !getUrlSegment(i).second; i++) {
  ------------------
  |  Branch (219:33): [True: 1.65k, False: 1.65k]
  ------------------
  220|       |                    /* Go to next segment or quit */
  221|  1.65k|                    std::string segment = std::string(getUrlSegment(i).first);
  222|  1.65k|                    Node *next = nullptr;
  223|  1.65k|                    for (std::unique_ptr<Node> &child : n->children) {
  ------------------
  |  Branch (223:55): [True: 1.65k, False: 0]
  ------------------
  224|  1.65k|                        if (child->name == segment && child->isHighPriority == (priority == HIGH_PRIORITY)) {
  ------------------
  |  Branch (224:29): [True: 1.65k, False: 0]
  |  Branch (224:55): [True: 1.65k, False: 0]
  ------------------
  225|  1.65k|                            next = child.get();
  226|  1.65k|                            break;
  227|  1.65k|                        }
  228|  1.65k|                    }
  229|  1.65k|                    if (!next) {
  ------------------
  |  Branch (229:25): [True: 0, False: 1.65k]
  ------------------
  230|      0|                        return UINT32_MAX;
  231|      0|                    }
  232|  1.65k|                    n = next;
  233|  1.65k|                }
  234|       |                /* Seek for a priority match in the found node */
  235|  1.65k|                for (unsigned int i = 0; i < n->handlers.size(); i++) {
  ------------------
  |  Branch (235:42): [True: 1.65k, False: 0]
  ------------------
  236|  1.65k|                    if ((n->handlers[i] & ~HANDLER_MASK) == priority) {
  ------------------
  |  Branch (236:25): [True: 1.65k, False: 0]
  ------------------
  237|  1.65k|                        return n->handlers[i];
  238|  1.65k|                    }
  239|  1.65k|                }
  240|      0|                return UINT32_MAX;
  241|  1.65k|            }
  242|  1.65k|        }
  243|      0|        return UINT32_MAX;
  244|  1.65k|    }
_ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE3addENSt3__16vectorINS5_12basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEENSA_ISC_EEEESC_ON5ofats13any_invocableIFbPS4_EEEj:
  281|  1.65k|    void add(std::vector<std::string> methods, std::string pattern, MoveOnlyFunction<bool(HttpRouter *)> &&handler, uint32_t priority = MEDIUM_PRIORITY) {
  282|  1.65k|        for (std::string method : methods) {
  ------------------
  |  Branch (282:33): [True: 1.65k, False: 1.65k]
  ------------------
  283|       |            /* Lookup method */
  284|  1.65k|            Node *node = getNode(&root, method, false);
  285|       |            /* Iterate over all segments */
  286|  1.65k|            setUrl(pattern);
  287|  3.31k|            for (int i = 0; !getUrlSegment(i).second; i++) {
  ------------------
  |  Branch (287:29): [True: 1.65k, False: 1.65k]
  ------------------
  288|  1.65k|                node = getNode(node, std::string(getUrlSegment(i).first), priority == HIGH_PRIORITY);
  289|  1.65k|            }
  290|       |            /* Insert handler in order sorted by priority (most significant 1 byte) */
  291|  1.65k|            node->handlers.insert(std::upper_bound(node->handlers.begin(), node->handlers.end(), (uint32_t) (priority | handlers.size())), (uint32_t) (priority | handlers.size()));
  292|  1.65k|        }
  293|       |
  294|       |        /* Alloate this handler */
  295|  1.65k|        handlers.emplace_back(std::move(handler));
  296|       |
  297|       |        /* Assume can find this handler again */
  298|  1.65k|        if (((handlers.size() - 1) | priority) != findHandler(methods[0], pattern, priority)) {
  ------------------
  |  Branch (298:13): [True: 0, False: 1.65k]
  ------------------
  299|      0|            std::cerr << "Error: Internal routing error" << std::endl;
  300|      0|            std::abort();
  301|      0|        }
  302|  1.65k|    }
_ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE7getNodeEPNS4_4NodeENSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEb:
   85|  3.31k|    Node *getNode(Node *parent, std::string child, bool isHighPriority) {
   86|  3.31k|        for (std::unique_ptr<Node> &node : parent->children) {
  ------------------
  |  Branch (86:42): [True: 0, False: 3.31k]
  ------------------
   87|      0|            if (node->name == child && node->isHighPriority == isHighPriority) {
  ------------------
  |  Branch (87:17): [True: 0, False: 0]
  |  Branch (87:40): [True: 0, False: 0]
  ------------------
   88|      0|                return node.get();
   89|      0|            }
   90|      0|        }
   91|       |
   92|       |        /* Insert sorted, but keep order if parent is root (we sort methods by priority elsewhere) */
   93|  3.31k|        std::unique_ptr<Node> newNode(new Node(child));
   94|  3.31k|        newNode->isHighPriority = isHighPriority;
   95|  3.31k|        return parent->children.emplace(std::upper_bound(parent->children.begin(), parent->children.end(), newNode, [parent, this](auto &a, auto &b) {
   96|       |
   97|  3.31k|            if (a->isHighPriority != b->isHighPriority) {
   98|  3.31k|                return a->isHighPriority;
   99|  3.31k|            }
  100|       |
  101|  3.31k|            return b->name.length() && (parent != &root) && (lexicalOrder(b->name) < lexicalOrder(a->name));
  102|  3.31k|        }), std::move(newNode))->get();
  103|  3.31k|    }
_ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE13getParametersEv:
  254|  23.2k|    std::pair<int, std::string_view *> getParameters() {
  255|  23.2k|        return {routeParameters.paramsTop, routeParameters.params};
  256|  23.2k|    }

_ZN3uWS4Loop3getEPv:
  111|  28.2k|    static Loop *get(void *existingNativeLoop = nullptr) {
  112|  28.2k|        if (!getLazyLoop().loop) {
  ------------------
  |  Branch (112:13): [True: 1.65k, False: 26.5k]
  ------------------
  113|       |            /* If we are given a native loop pointer we pass that to uSockets and let it deal with it */
  114|  1.65k|            if (existingNativeLoop) {
  ------------------
  |  Branch (114:17): [True: 0, False: 1.65k]
  ------------------
  115|       |                /* Todo: here we want to pass the pointer, not a boolean */
  116|      0|                getLazyLoop().loop = create(existingNativeLoop);
  117|       |                /* We cannot register automatic free here, must be manually done */
  118|  1.65k|            } else {
  119|  1.65k|                getLazyLoop().loop = create(nullptr);
  120|  1.65k|                getLazyLoop().cleanMe = true;
  121|  1.65k|            }
  122|  1.65k|        }
  123|       |
  124|  28.2k|        return getLazyLoop().loop;
  125|  28.2k|    }
_ZN3uWS4Loop11getLazyLoopEv:
  103|  61.3k|    static LoopCleaner &getLazyLoop() {
  104|  61.3k|        static thread_local LoopCleaner lazyLoop;
  105|  61.3k|        return lazyLoop;
  106|  61.3k|    }
_ZN3uWS4Loop11LoopCleanerD2Ev:
   94|      1|        ~LoopCleaner() {
   95|      1|            if(loop && cleanMe) {
  ------------------
  |  Branch (95:16): [True: 0, False: 1]
  |  Branch (95:24): [True: 0, False: 0]
  ------------------
   96|      0|                loop->free();
   97|      0|            }
   98|      1|        }
_ZN3uWS4Loop6createEPv:
   76|  1.65k|    static Loop *create(void *hint) {
   77|  1.65k|        Loop *loop = ((Loop *) us_create_loop(hint, wakeupCb, preCb, postCb, sizeof(LoopData)))->init();
   78|       |
   79|       |        /* We also need some timers (should live off the one 4 second timer rather) */
   80|  1.65k|        LoopData *loopData = (LoopData *) us_loop_ext((struct us_loop_t *) loop);
   81|  1.65k|        loopData->dateTimer = us_create_timer((struct us_loop_t *) loop, 1, sizeof(LoopData *));
   82|  1.65k|        memcpy(us_timer_ext(loopData->dateTimer), &loopData, sizeof(LoopData *));
   83|  1.65k|        us_timer_set(loopData->dateTimer, [](struct us_timer_t *t) {
   84|  1.65k|            LoopData *loopData;
   85|  1.65k|            memcpy(&loopData, us_timer_ext(t), sizeof(LoopData *));
   86|  1.65k|            loopData->updateDate();
   87|  1.65k|        }, 1000, 1000);
   88|       |
   89|  1.65k|        return loop;
   90|  1.65k|    }
_ZN3uWS4Loop8wakeupCbEP9us_loop_t:
   30|  2.04M|    static void wakeupCb(us_loop_t *loop) {
   31|  2.04M|        LoopData *loopData = (LoopData *) us_loop_ext(loop);
   32|       |
   33|       |        /* Swap current deferQueue */
   34|  2.04M|        loopData->deferMutex.lock();
   35|  2.04M|        int oldDeferQueue = loopData->currentDeferQueue;
   36|  2.04M|        loopData->currentDeferQueue = (loopData->currentDeferQueue + 1) % 2;
   37|  2.04M|        loopData->deferMutex.unlock();
   38|       |
   39|       |        /* Drain the queue */
   40|  2.04M|        for (auto &x : loopData->deferQueues[oldDeferQueue]) {
  ------------------
  |  Branch (40:22): [True: 22.6k, False: 2.04M]
  ------------------
   41|  22.6k|            x();
   42|  22.6k|        }
   43|  2.04M|        loopData->deferQueues[oldDeferQueue].clear();
   44|  2.04M|    }
_ZN3uWS4Loop5preCbEP9us_loop_t:
   46|  2.55M|    static void preCb(us_loop_t *loop) {
   47|  2.55M|        LoopData *loopData = (LoopData *) us_loop_ext(loop);
   48|       |
   49|  2.55M|        for (auto &p : loopData->preHandlers) {
  ------------------
  |  Branch (49:22): [True: 0, False: 2.55M]
  ------------------
   50|      0|            p.second((Loop *) loop);
   51|      0|        }
   52|  2.55M|    }
_ZN3uWS4Loop6postCbEP9us_loop_t:
   54|  2.55M|    static void postCb(us_loop_t *loop) {
   55|  2.55M|        LoopData *loopData = (LoopData *) us_loop_ext(loop);
   56|       |
   57|  2.55M|        for (auto &p : loopData->postHandlers) {
  ------------------
  |  Branch (57:22): [True: 0, False: 2.55M]
  ------------------
   58|      0|            p.second((Loop *) loop);
   59|      0|        }
   60|       |
   61|       |        /* After every event loop iteration, we must not hold the cork buffer */
   62|  2.55M|        if (loopData->corkedSocket) {
  ------------------
  |  Branch (62:13): [True: 0, False: 2.55M]
  ------------------
   63|      0|            std::cerr << "Error: Cork buffer must not be held across event loop iterations!" << std::endl;
   64|      0|            std::terminate();
   65|      0|        }
   66|  2.55M|    }
_ZN3uWS4Loop4initEv:
   71|  1.65k|    Loop *init() {
   72|  1.65k|        new (us_loop_ext((us_loop_t *) this)) LoopData;
   73|  1.65k|        return this;
   74|  1.65k|    }
_ZZN3uWS4Loop6createEPvENKUlP10us_timer_tE_clES3_:
   83|  2.04M|        us_timer_set(loopData->dateTimer, [](struct us_timer_t *t) {
   84|  2.04M|            LoopData *loopData;
   85|  2.04M|            memcpy(&loopData, us_timer_ext(t), sizeof(LoopData *));
   86|  2.04M|            loopData->updateDate();
   87|  2.04M|        }, 1000, 1000);
_ZN3uWS4Loop4freeEv:
  128|  1.65k|    void free() {
  129|  1.65k|        LoopData *loopData = (LoopData *) us_loop_ext((us_loop_t *) this);
  130|       |
  131|       |        /* Stop and free dateTimer first */
  132|  1.65k|        us_timer_close(loopData->dateTimer);
  133|       |
  134|  1.65k|        loopData->~LoopData();
  135|       |        /* uSockets will track whether this loop is owned by us or a borrowed alien loop */
  136|  1.65k|        us_loop_free((us_loop_t *) this);
  137|       |
  138|       |        /* Reset lazyLoop */
  139|  1.65k|        getLazyLoop().loop = nullptr;
  140|  1.65k|    }
_ZN3uWS4Loop5deferEON5ofats13any_invocableIFvvEEE:
  169|  23.2k|    void defer(MoveOnlyFunction<void()> &&cb) {
  170|  23.2k|        LoopData *loopData = (LoopData *) us_loop_ext((us_loop_t *) this);
  171|       |
  172|       |        //if (std::thread::get_id() == ) // todo: add fast path for same thread id
  173|  23.2k|        loopData->deferMutex.lock();
  174|  23.2k|        loopData->deferQueues[loopData->currentDeferQueue].emplace_back(std::move(cb));
  175|  23.2k|        loopData->deferMutex.unlock();
  176|       |
  177|  23.2k|        us_wakeup_loop((us_loop_t *) this);
  178|  23.2k|    }
_ZN3uWS3runEv:
  198|  1.65k|inline void run() {
  199|  1.65k|    Loop::get()->run();
  200|  1.65k|}
_ZN3uWS4Loop3runEv:
  181|  1.65k|    void run() {
  182|  1.65k|        us_loop_run((us_loop_t *) this);
  183|  1.65k|    }

_ZN3uWS8LoopDataC2Ev:
   49|  1.65k|    LoopData() {
   50|  1.65k|        updateDate();
   51|  1.65k|    }
_ZN3uWS8LoopData10updateDateEv:
   63|  2.04M|    void updateDate() {
   64|  2.04M|        time_t now = time(0);
   65|  2.04M|        struct tm tstruct = {};
   66|       |#ifdef _WIN32
   67|       |        /* Micro, fucking soft never follows spec. */
   68|       |        gmtime_s(&tstruct, &now);
   69|       |#else
   70|  2.04M|        gmtime_r(&now, &tstruct);
   71|  2.04M|#endif
   72|  2.04M|        static const char wday_name[][4] = {
   73|  2.04M|            "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
   74|  2.04M|        };
   75|  2.04M|        static const char mon_name[][4] = {
   76|  2.04M|            "Jan", "Feb", "Mar", "Apr", "May", "Jun",
   77|  2.04M|            "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
   78|  2.04M|        };
   79|  2.04M|        snprintf(date, 32, "%.3s, %.2u %.3s %.4u %.2u:%.2u:%.2u GMT",
   80|  2.04M|            wday_name[tstruct.tm_wday],
   81|  2.04M|            tstruct.tm_mday % 99,
   82|  2.04M|            mon_name[tstruct.tm_mon],
   83|  2.04M|            (1900 + tstruct.tm_year) % 9999,
   84|  2.04M|            tstruct.tm_hour % 99,
   85|  2.04M|            tstruct.tm_min % 99,
   86|  2.04M|            tstruct.tm_sec % 99);
   87|  2.04M|    }
_ZN3uWS8LoopDataD2Ev:
   53|  1.65k|    ~LoopData() {
   54|       |        /* If we have had App.ws called with compression we need to clear this */
   55|  1.65k|        if (zlibContext) {
  ------------------
  |  Branch (55:13): [True: 0, False: 1.65k]
  ------------------
   56|      0|            delete zlibContext;
   57|      0|            delete inflationStream;
   58|      0|            delete deflationStream;
   59|      0|        }
   60|  1.65k|        delete [] corkBuffer;
   61|  1.65k|    }

_ZN5ofats10any_detail18any_invocable_implIvLb0EJP18us_listen_socket_tEED2Ev:
  206|  1.65k|  ~any_invocable_impl() { destroy(); }
_ZN5ofats10any_detail18any_invocable_implIvLb0EJP18us_listen_socket_tEE7destroyEv:
  239|  1.65k|  void destroy() noexcept {
  240|  1.65k|    if (handle_) {
  ------------------
  |  Branch (240:9): [True: 1.65k, False: 0]
  ------------------
  241|  1.65k|      handle_(action::destroy, &storage_, nullptr);
  242|  1.65k|      handle_ = nullptr;
  243|  1.65k|    }
  244|  1.65k|  }
_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEED2Ev:
  206|  4.96k|  ~any_invocable_impl() { destroy(); }
_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEE7destroyEv:
  239|  4.96k|  void destroy() noexcept {
  240|  4.96k|    if (handle_) {
  ------------------
  |  Branch (240:9): [True: 1.65k, False: 3.31k]
  ------------------
  241|  1.65k|      handle_(action::destroy, &storage_, nullptr);
  242|  1.65k|      handle_ = nullptr;
  243|  1.65k|    }
  244|  4.96k|  }
_ZN5ofats13any_invocableIFvvEEclEv:
  345|  45.8k|    R operator()(ArgTypes... args) cv ref noexcept(noex) {                     \
  346|  45.8k|      return base_type::call(std::forward<ArgTypes>(args)...);                 \
  347|  45.8k|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIvLb0EJEE4callEv:
  246|  45.8k|  R call(ArgTypes... args) noexcept(is_noexcept) {
  247|  45.8k|    return call_(storage_, std::forward<ArgTypes>(args)...);
  248|  45.8k|  }
_ZN5ofats10any_detail18any_invocable_implIvLb0EJEED2Ev:
  206|  1.13M|  ~any_invocable_impl() { destroy(); }
_ZN5ofats10any_detail18any_invocable_implIvLb0EJEE7destroyEv:
  239|  1.13M|  void destroy() noexcept {
  240|  1.13M|    if (handle_) {
  ------------------
  |  Branch (240:9): [True: 59.5k, False: 1.07M]
  ------------------
  241|  59.5k|      handle_(action::destroy, &storage_, nullptr);
  242|  59.5k|      handle_ = nullptr;
  243|  59.5k|    }
  244|  1.13M|  }
_ZN5ofats10any_detail18any_invocable_implIvLb0EJPKcEEC2Ev:
  186|  1.65k|  any_invocable_impl() noexcept = default;
_ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterINS2_15HttpContextDataILb0EE10RouterDataEEEEED2Ev:
  206|  3.31k|  ~any_invocable_impl() { destroy(); }
_ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterINS2_15HttpContextDataILb0EE10RouterDataEEEEE7destroyEv:
  239|  3.31k|  void destroy() noexcept {
  240|  3.31k|    if (handle_) {
  ------------------
  |  Branch (240:9): [True: 1.65k, False: 1.65k]
  ------------------
  241|  1.65k|      handle_(action::destroy, &storage_, nullptr);
  242|  1.65k|      handle_ = nullptr;
  243|  1.65k|    }
  244|  3.31k|  }
_ZN5ofats10any_detail18any_invocable_implIvLb0EJPKcEED2Ev:
  206|  1.65k|  ~any_invocable_impl() { destroy(); }
_ZN5ofats10any_detail18any_invocable_implIvLb0EJPKcEE7destroyEv:
  239|  1.65k|  void destroy() noexcept {
  240|  1.65k|    if (handle_) {
  ------------------
  |  Branch (240:9): [True: 0, False: 1.65k]
  ------------------
  241|      0|      handle_(action::destroy, &storage_, nullptr);
  242|      0|      handle_ = nullptr;
  243|      0|    }
  244|  1.65k|  }
_ZN5ofats10any_detail18any_invocable_implIbLb0EJmEEC2Ev:
  186|  1.01M|  any_invocable_impl() noexcept = default;
_ZN5ofats10any_detail18any_invocable_implIvLb0EJEEC2Ev:
  186|  1.06M|  any_invocable_impl() noexcept = default;
_ZN5ofats10any_detail18any_invocable_implIvLb0EJNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEbEEC2Ev:
  186|  1.01M|  any_invocable_impl() noexcept = default;
_ZNK5ofats10any_detail18any_invocable_implIvLb0EJEEcvbEv:
  228|  1.03M|  explicit operator bool() const noexcept { return handle_ != nullptr; }
_ZN5ofats10any_detail18any_invocable_implIvLb0EJNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEbEED2Ev:
  206|  1.01M|  ~any_invocable_impl() { destroy(); }
_ZN5ofats10any_detail18any_invocable_implIvLb0EJNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEbEE7destroyEv:
  239|  1.01M|  void destroy() noexcept {
  240|  1.01M|    if (handle_) {
  ------------------
  |  Branch (240:9): [True: 0, False: 1.01M]
  ------------------
  241|      0|      handle_(action::destroy, &storage_, nullptr);
  242|      0|      handle_ = nullptr;
  243|      0|    }
  244|  1.01M|  }
_ZN5ofats10any_detail18any_invocable_implIbLb0EJmEED2Ev:
  206|  1.02M|  ~any_invocable_impl() { destroy(); }
_ZN5ofats10any_detail18any_invocable_implIbLb0EJmEE7destroyEv:
  239|  1.02M|  void destroy() noexcept {
  240|  1.02M|    if (handle_) {
  ------------------
  |  Branch (240:9): [True: 0, False: 1.02M]
  ------------------
  241|      0|      handle_(action::destroy, &storage_, nullptr);
  242|      0|      handle_ = nullptr;
  243|      0|    }
  244|  1.02M|  }
_ZN5ofats13any_invocableIFPvS1_NSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEbEEclES1_S6_b:
  345|  23.2k|    R operator()(ArgTypes... args) cv ref noexcept(noex) {                     \
  346|  23.2k|      return base_type::call(std::forward<ArgTypes>(args)...);                 \
  347|  23.2k|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE4callES2_S7_b:
  246|  23.2k|  R call(ArgTypes... args) noexcept(is_noexcept) {
  247|  23.2k|    return call_(storage_, std::forward<ArgTypes>(args)...);
  248|  23.2k|  }
_ZN5ofats13any_invocableIFPvS1_PN3uWS11HttpRequestEEEclES1_S4_:
  345|  27.4k|    R operator()(ArgTypes... args) cv ref noexcept(noex) {                     \
  346|  27.4k|      return base_type::call(std::forward<ArgTypes>(args)...);                 \
  347|  27.4k|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_PN3uWS11HttpRequestEEE4callES2_S5_:
  246|  27.4k|  R call(ArgTypes... args) noexcept(is_noexcept) {
  247|  27.4k|    return call_(storage_, std::forward<ArgTypes>(args)...);
  248|  27.4k|  }
_ZN5ofats13any_invocableIFPvS1_PN3uWS11HttpRequestEEEC2IZZNS2_11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clESB_SC_iEUlS1_S4_E_vEEOT_:
  303|   132k|    any_invocable(F&& f) {                                                     \
  304|   132k|      base_type::template create<std::decay_t<F>>(std::forward<F>(f));         \
  305|   132k|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_PN3uWS11HttpRequestEEEC2Ev:
  186|   132k|  any_invocable_impl() noexcept = default;
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_PN3uWS11HttpRequestEEE6createIZZNS3_11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clESB_SC_iEUlS2_S5_E_JSE_EEEvDpOT0_:
  232|   132k|  void create(Args&&... args) {
  233|   132k|    using hdl = handler<F>;
  234|   132k|    hdl::create(storage_, std::forward<Args>(args)...);
  235|   132k|    handle_ = &hdl::handle;
  236|   132k|    call_ = &hdl::call;
  237|   132k|  }
_ZN5ofats10any_detail14handler_traitsIPvJS2_PN3uWS11HttpRequestEEE13small_handlerIZZNS3_11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clESB_SC_iEUlS2_S5_E_E6createIJSE_EEEvRNS0_7storageEDpOT_:
  118|   132k|    static void create(storage& s, Args&&... args) {
  119|   132k|      new (static_cast<void*>(&s.buf_)) T(std::forward<Args>(args)...);
  120|   132k|    }
_ZN5ofats10any_detail14handler_traitsIPvJS2_PN3uWS11HttpRequestEEE12handler_baseINS6_13small_handlerIZZNS3_11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clESC_SD_iEUlS2_S5_E_EEE6handleENS0_6actionEPNS0_7storageESK_:
  103|   132k|    static void handle(action act, storage* current, storage* other = nullptr) {
  104|   132k|      switch (act) {
  ------------------
  |  Branch (104:15): [True: 0, False: 132k]
  ------------------
  105|   132k|        case (action::destroy):
  ------------------
  |  Branch (105:9): [True: 132k, False: 0]
  ------------------
  106|   132k|          Derived::destroy(*current);
  107|   132k|          break;
  108|      0|        case (action::move):
  ------------------
  |  Branch (108:9): [True: 0, False: 132k]
  ------------------
  109|      0|          Derived::move(*current, *other);
  110|      0|          break;
  111|   132k|      }
  112|   132k|    }
_ZN5ofats10any_detail14handler_traitsIPvJS2_PN3uWS11HttpRequestEEE13small_handlerIZZNS3_11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clESB_SC_iEUlS2_S5_E_E7destroyERNS0_7storageE:
  122|   132k|    static void destroy(storage& s) noexcept {
  123|   132k|      T& value = *static_cast<T*>(static_cast<void*>(&s.buf_));
  124|   132k|      value.~T();
  125|   132k|    }
_ZN5ofats10any_detail14handler_traitsIPvJS2_PN3uWS11HttpRequestEEE13small_handlerIZZNS3_11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clESB_SC_iEUlS2_S5_E_E4callERNS0_7storageES2_S5_:
  132|  27.4k|    static R call(storage& s, ArgTypes... args) {
  133|  27.4k|      return std::invoke(*static_cast<T*>(static_cast<void*>(&s.buf_)),
  134|  27.4k|                         std::forward<ArgTypes>(args)...);
  135|  27.4k|    }
_ZN5ofats13any_invocableIFbPN3uWS10HttpRouterINS1_15HttpContextDataILb0EE10RouterDataEEEEEclES7_:
  345|  23.2k|    R operator()(ArgTypes... args) cv ref noexcept(noex) {                     \
  346|  23.2k|      return base_type::call(std::forward<ArgTypes>(args)...);                 \
  347|  23.2k|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterINS2_15HttpContextDataILb0EE10RouterDataEEEEE4callES8_:
  246|  23.2k|  R call(ArgTypes... args) noexcept(is_noexcept) {
  247|  23.2k|    return call_(storage_, std::forward<ArgTypes>(args)...);
  248|  23.2k|  }
_ZNK5ofats10any_detail18any_invocable_implIvLb0EJNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEbEEcvbEv:
  228|  46.4k|  explicit operator bool() const noexcept { return handle_ != nullptr; }
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_PN3uWS11HttpRequestEEED2Ev:
  206|   132k|  ~any_invocable_impl() { destroy(); }
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_PN3uWS11HttpRequestEEE7destroyEv:
  239|   132k|  void destroy() noexcept {
  240|   132k|    if (handle_) {
  ------------------
  |  Branch (240:9): [True: 132k, False: 0]
  ------------------
  241|   132k|      handle_(action::destroy, &storage_, nullptr);
  242|   132k|      handle_ = nullptr;
  243|   132k|    }
  244|   132k|  }
_ZN5ofats13any_invocableIFPvS1_NSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEbEEC2IZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clESE_SF_iEUlS1_S6_bE_vEEOT_:
  303|   132k|    any_invocable(F&& f) {                                                     \
  304|   132k|      base_type::template create<std::decay_t<F>>(std::forward<F>(f));         \
  305|   132k|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEEC2Ev:
  186|   132k|  any_invocable_impl() noexcept = default;
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE6createIZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clESE_SF_iEUlS2_S7_bE_JSH_EEEvDpOT0_:
  232|   132k|  void create(Args&&... args) {
  233|   132k|    using hdl = handler<F>;
  234|   132k|    hdl::create(storage_, std::forward<Args>(args)...);
  235|   132k|    handle_ = &hdl::handle;
  236|   132k|    call_ = &hdl::call;
  237|   132k|  }
_ZN5ofats10any_detail14handler_traitsIPvJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE13small_handlerIZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clESE_SF_iEUlS2_S7_bE_E6createIJSH_EEEvRNS0_7storageEDpOT_:
  118|   132k|    static void create(storage& s, Args&&... args) {
  119|   132k|      new (static_cast<void*>(&s.buf_)) T(std::forward<Args>(args)...);
  120|   132k|    }
_ZN5ofats10any_detail14handler_traitsIPvJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE12handler_baseINS8_13small_handlerIZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clESF_SG_iEUlS2_S7_bE_EEE6handleENS0_6actionEPNS0_7storageESN_:
  103|   132k|    static void handle(action act, storage* current, storage* other = nullptr) {
  104|   132k|      switch (act) {
  ------------------
  |  Branch (104:15): [True: 0, False: 132k]
  ------------------
  105|   132k|        case (action::destroy):
  ------------------
  |  Branch (105:9): [True: 132k, False: 0]
  ------------------
  106|   132k|          Derived::destroy(*current);
  107|   132k|          break;
  108|      0|        case (action::move):
  ------------------
  |  Branch (108:9): [True: 0, False: 132k]
  ------------------
  109|      0|          Derived::move(*current, *other);
  110|      0|          break;
  111|   132k|      }
  112|   132k|    }
_ZN5ofats10any_detail14handler_traitsIPvJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE13small_handlerIZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clESE_SF_iEUlS2_S7_bE_E7destroyERNS0_7storageE:
  122|   132k|    static void destroy(storage& s) noexcept {
  123|   132k|      T& value = *static_cast<T*>(static_cast<void*>(&s.buf_));
  124|   132k|      value.~T();
  125|   132k|    }
_ZN5ofats10any_detail14handler_traitsIPvJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE13small_handlerIZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clESE_SF_iEUlS2_S7_bE_E4callERNS0_7storageES2_S7_b:
  132|  23.2k|    static R call(storage& s, ArgTypes... args) {
  133|  23.2k|      return std::invoke(*static_cast<T*>(static_cast<void*>(&s.buf_)),
  134|  23.2k|                         std::forward<ArgTypes>(args)...);
  135|  23.2k|    }
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEED2Ev:
  206|   132k|  ~any_invocable_impl() { destroy(); }
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE7destroyEv:
  239|   132k|  void destroy() noexcept {
  240|   132k|    if (handle_) {
  ------------------
  |  Branch (240:9): [True: 132k, False: 0]
  ------------------
  241|   132k|      handle_(action::destroy, &storage_, nullptr);
  242|   132k|      handle_ = nullptr;
  243|   132k|    }
  244|   132k|  }
_ZNK5ofats10any_detail18any_invocable_implIbLb0EJmEEcvbEv:
  228|  10.5k|  explicit operator bool() const noexcept { return handle_ != nullptr; }
_ZN5ofats10any_detail18any_invocable_implIbLb0EJmEE4swapERS2_:
  208|  13.0k|  void swap(any_invocable_impl& rhs) noexcept {
  209|  13.0k|    if (handle_) {
  ------------------
  |  Branch (209:9): [True: 0, False: 13.0k]
  ------------------
  210|      0|      if (rhs.handle_) {
  ------------------
  |  Branch (210:11): [True: 0, False: 0]
  ------------------
  211|      0|        storage tmp;
  212|      0|        handle_(action::move, &tmp, &storage_);
  213|      0|        rhs.handle_(action::move, &storage_, &rhs.storage_);
  214|      0|        handle_(action::move, &rhs.storage_, &tmp);
  215|      0|        std::swap(handle_, rhs.handle_);
  216|      0|        std::swap(call_, rhs.call_);
  217|      0|      } else {
  218|      0|        rhs.swap(*this);
  219|      0|      }
  220|  13.0k|    } else if (rhs.handle_) {
  ------------------
  |  Branch (220:16): [True: 0, False: 13.0k]
  ------------------
  221|      0|      rhs.handle_(action::move, &storage_, &rhs.storage_);
  222|      0|      handle_ = rhs.handle_;
  223|      0|      call_ = rhs.call_;
  224|      0|      rhs.handle_ = nullptr;
  225|      0|    }
  226|  13.0k|  }
_ZNK5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEEcvbEv:
  228|  1.65k|  explicit operator bool() const noexcept { return handle_ != nullptr; }
_ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterINS2_15HttpContextDataILb0EE10RouterDataEEEEEC2EOS9_:
  188|  1.65k|  any_invocable_impl(any_invocable_impl&& rhs) noexcept {
  189|  1.65k|    if (rhs.handle_) {
  ------------------
  |  Branch (189:9): [True: 1.65k, False: 0]
  ------------------
  190|  1.65k|      handle_ = rhs.handle_;
  191|  1.65k|      handle_(action::move, &storage_, &rhs.storage_);
  192|  1.65k|      call_ = rhs.call_;
  193|  1.65k|      rhs.handle_ = nullptr;
  194|  1.65k|    }
  195|  1.65k|  }
_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEEC2EOS8_:
  188|  3.31k|  any_invocable_impl(any_invocable_impl&& rhs) noexcept {
  189|  3.31k|    if (rhs.handle_) {
  ------------------
  |  Branch (189:9): [True: 3.31k, False: 0]
  ------------------
  190|  3.31k|      handle_ = rhs.handle_;
  191|  3.31k|      handle_(action::move, &storage_, &rhs.storage_);
  192|  3.31k|      call_ = rhs.call_;
  193|  3.31k|      rhs.handle_ = nullptr;
  194|  3.31k|    }
  195|  3.31k|  }
_ZN5ofats13any_invocableIFbPN3uWS10HttpRouterINS1_15HttpContextDataILb0EE10RouterDataEEEEEC2IZNS1_11HttpContextILb0EE6onHttpENSt3__112basic_stringIcNSD_11char_traitsIcEENSD_9allocatorIcEEEESJ_ONS0_IFvPNS1_12HttpResponseILb0EEEPNS1_11HttpRequestEEEEbEUlPT_E_vEEOSS_:
  303|  1.65k|    any_invocable(F&& f) {                                                     \
  304|  1.65k|      base_type::template create<std::decay_t<F>>(std::forward<F>(f));         \
  305|  1.65k|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterINS2_15HttpContextDataILb0EE10RouterDataEEEEEC2Ev:
  186|  1.65k|  any_invocable_impl() noexcept = default;
_ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterINS2_15HttpContextDataILb0EE10RouterDataEEEEE6createIZNS2_11HttpContextILb0EE6onHttpENSt3__112basic_stringIcNSD_11char_traitsIcEENSD_9allocatorIcEEEESJ_ONS_13any_invocableIFvPNS2_12HttpResponseILb0EEEPNS2_11HttpRequestEEEEbEUlPT_E_JSV_EEEvDpOT0_:
  232|  1.65k|  void create(Args&&... args) {
  233|  1.65k|    using hdl = handler<F>;
  234|  1.65k|    hdl::create(storage_, std::forward<Args>(args)...);
  235|  1.65k|    handle_ = &hdl::handle;
  236|  1.65k|    call_ = &hdl::call;
  237|  1.65k|  }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterINS2_15HttpContextDataILb0EE10RouterDataEEEEE13large_handlerIZNS2_11HttpContextILb0EE6onHttpENSt3__112basic_stringIcNSD_11char_traitsIcEENSD_9allocatorIcEEEESJ_ONS_13any_invocableIFvPNS2_12HttpResponseILb0EEEPNS2_11HttpRequestEEEEbEUlPT_E_E6createIJSV_EEEvRNS0_7storageEDpOT_:
  141|  1.65k|    static void create(storage& s, Args&&... args) {
  142|  1.65k|      s.ptr_ = new T(std::forward<Args>(args)...);
  143|  1.65k|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterINS2_15HttpContextDataILb0EE10RouterDataEEEEE12handler_baseINS9_13large_handlerIZNS2_11HttpContextILb0EE6onHttpENSt3__112basic_stringIcNSE_11char_traitsIcEENSE_9allocatorIcEEEESK_ONS_13any_invocableIFvPNS2_12HttpResponseILb0EEEPNS2_11HttpRequestEEEEbEUlPT_E_EEE6handleENS0_6actionEPNS0_7storageES11_:
  103|  3.31k|    static void handle(action act, storage* current, storage* other = nullptr) {
  104|  3.31k|      switch (act) {
  ------------------
  |  Branch (104:15): [True: 0, False: 3.31k]
  ------------------
  105|  1.65k|        case (action::destroy):
  ------------------
  |  Branch (105:9): [True: 1.65k, False: 1.65k]
  ------------------
  106|  1.65k|          Derived::destroy(*current);
  107|  1.65k|          break;
  108|  1.65k|        case (action::move):
  ------------------
  |  Branch (108:9): [True: 1.65k, False: 1.65k]
  ------------------
  109|  1.65k|          Derived::move(*current, *other);
  110|  1.65k|          break;
  111|  3.31k|      }
  112|  3.31k|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterINS2_15HttpContextDataILb0EE10RouterDataEEEEE13large_handlerIZNS2_11HttpContextILb0EE6onHttpENSt3__112basic_stringIcNSD_11char_traitsIcEENSD_9allocatorIcEEEESJ_ONS_13any_invocableIFvPNS2_12HttpResponseILb0EEEPNS2_11HttpRequestEEEEbEUlPT_E_E7destroyERNS0_7storageE:
  145|  1.65k|    static void destroy(storage& s) noexcept { delete static_cast<T*>(s.ptr_); }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterINS2_15HttpContextDataILb0EE10RouterDataEEEEE13large_handlerIZNS2_11HttpContextILb0EE6onHttpENSt3__112basic_stringIcNSD_11char_traitsIcEENSD_9allocatorIcEEEESJ_ONS_13any_invocableIFvPNS2_12HttpResponseILb0EEEPNS2_11HttpRequestEEEEbEUlPT_E_E4moveERNS0_7storageESY_:
  147|  1.65k|    static void move(storage& dst, storage& src) noexcept {
  148|  1.65k|      dst.ptr_ = src.ptr_;
  149|  1.65k|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterINS2_15HttpContextDataILb0EE10RouterDataEEEEE13large_handlerIZNS2_11HttpContextILb0EE6onHttpENSt3__112basic_stringIcNSD_11char_traitsIcEENSD_9allocatorIcEEEESJ_ONS_13any_invocableIFvPNS2_12HttpResponseILb0EEEPNS2_11HttpRequestEEEEbEUlPT_E_E4callERNS0_7storageES8_:
  151|  23.2k|    static R call(storage& s, ArgTypes... args) {
  152|  23.2k|      return std::invoke(*static_cast<T*>(s.ptr_),
  153|  23.2k|                         std::forward<ArgTypes>(args)...);
  154|  23.2k|    }
_ZN5ofats13any_invocableIFvPN3uWS12HttpResponseILb0EEEPNS1_11HttpRequestEEEclES4_S6_:
  345|  23.2k|    R operator()(ArgTypes... args) cv ref noexcept(noex) {                     \
  346|  23.2k|      return base_type::call(std::forward<ArgTypes>(args)...);                 \
  347|  23.2k|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEE4callES5_S7_:
  246|  23.2k|  R call(ArgTypes... args) noexcept(is_noexcept) {
  247|  23.2k|    return call_(storage_, std::forward<ArgTypes>(args)...);
  248|  23.2k|  }
AsyncEpollHelloWorld.cpp:_ZN5ofats13any_invocableIFvPN3uWS12HttpResponseILb0EEEPNS1_11HttpRequestEEEC2IZ4testvE3$_0vEEOT_:
  303|  1.65k|    any_invocable(F&& f) {                                                     \
  304|  1.65k|      base_type::template create<std::decay_t<F>>(std::forward<F>(f));         \
  305|  1.65k|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEEC2Ev:
  186|  1.65k|  any_invocable_impl() noexcept = default;
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEE6createIZ4testvE3$_0JSA_EEEvDpOT0_:
  232|  1.65k|  void create(Args&&... args) {
  233|  1.65k|    using hdl = handler<F>;
  234|  1.65k|    hdl::create(storage_, std::forward<Args>(args)...);
  235|  1.65k|    handle_ = &hdl::handle;
  236|  1.65k|    call_ = &hdl::call;
  237|  1.65k|  }
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEE13small_handlerIZ4testvE3$_0E6createIJSA_EEEvRNS0_7storageEDpOT_:
  118|  4.96k|    static void create(storage& s, Args&&... args) {
  119|  4.96k|      new (static_cast<void*>(&s.buf_)) T(std::forward<Args>(args)...);
  120|  4.96k|    }
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEE12handler_baseINS8_13small_handlerIZ4testvE3$_0EEE6handleENS0_6actionEPNS0_7storageESG_:
  103|  4.96k|    static void handle(action act, storage* current, storage* other = nullptr) {
  104|  4.96k|      switch (act) {
  ------------------
  |  Branch (104:15): [True: 0, False: 4.96k]
  ------------------
  105|  1.65k|        case (action::destroy):
  ------------------
  |  Branch (105:9): [True: 1.65k, False: 3.31k]
  ------------------
  106|  1.65k|          Derived::destroy(*current);
  107|  1.65k|          break;
  108|  3.31k|        case (action::move):
  ------------------
  |  Branch (108:9): [True: 3.31k, False: 1.65k]
  ------------------
  109|  3.31k|          Derived::move(*current, *other);
  110|  3.31k|          break;
  111|  4.96k|      }
  112|  4.96k|    }
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEE13small_handlerIZ4testvE3$_0E7destroyERNS0_7storageE:
  122|  4.96k|    static void destroy(storage& s) noexcept {
  123|  4.96k|      T& value = *static_cast<T*>(static_cast<void*>(&s.buf_));
  124|  4.96k|      value.~T();
  125|  4.96k|    }
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEE13small_handlerIZ4testvE3$_0E4moveERNS0_7storageESD_:
  127|  3.31k|    static void move(storage& dst, storage& src) noexcept {
  128|  3.31k|      create(dst, std::move(*static_cast<T*>(static_cast<void*>(&src.buf_))));
  129|  3.31k|      destroy(src);
  130|  3.31k|    }
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEE13small_handlerIZ4testvE3$_0E4callERNS0_7storageES5_S7_:
  132|  23.2k|    static R call(storage& s, ArgTypes... args) {
  133|  23.2k|      return std::invoke(*static_cast<T*>(static_cast<void*>(&s.buf_)),
  134|  23.2k|                         std::forward<ArgTypes>(args)...);
  135|  23.2k|    }
_ZN5ofats10any_detail18any_invocable_implIvLb0EJEEaSEOS2_:
  197|  23.2k|  any_invocable_impl& operator=(any_invocable_impl&& rhs) noexcept {
  198|  23.2k|    any_invocable_impl{std::move(rhs)}.swap(*this);
  199|  23.2k|    return *this;
  200|  23.2k|  }
_ZN5ofats10any_detail18any_invocable_implIvLb0EJEEC2EOS2_:
  188|  50.4k|  any_invocable_impl(any_invocable_impl&& rhs) noexcept {
  189|  50.4k|    if (rhs.handle_) {
  ------------------
  |  Branch (189:9): [True: 50.4k, False: 0]
  ------------------
  190|  50.4k|      handle_ = rhs.handle_;
  191|  50.4k|      handle_(action::move, &storage_, &rhs.storage_);
  192|  50.4k|      call_ = rhs.call_;
  193|  50.4k|      rhs.handle_ = nullptr;
  194|  50.4k|    }
  195|  50.4k|  }
_ZN5ofats10any_detail18any_invocable_implIvLb0EJEE4swapERS2_:
  208|  59.5k|  void swap(any_invocable_impl& rhs) noexcept {
  209|  59.5k|    if (handle_) {
  ------------------
  |  Branch (209:9): [True: 23.2k, False: 36.3k]
  ------------------
  210|  23.2k|      if (rhs.handle_) {
  ------------------
  |  Branch (210:11): [True: 0, False: 23.2k]
  ------------------
  211|      0|        storage tmp;
  212|      0|        handle_(action::move, &tmp, &storage_);
  213|      0|        rhs.handle_(action::move, &storage_, &rhs.storage_);
  214|      0|        handle_(action::move, &rhs.storage_, &tmp);
  215|      0|        std::swap(handle_, rhs.handle_);
  216|      0|        std::swap(call_, rhs.call_);
  217|  23.2k|      } else {
  218|  23.2k|        rhs.swap(*this);
  219|  23.2k|      }
  220|  36.3k|    } else if (rhs.handle_) {
  ------------------
  |  Branch (220:16): [True: 36.3k, False: 0]
  ------------------
  221|  36.3k|      rhs.handle_(action::move, &storage_, &rhs.storage_);
  222|  36.3k|      handle_ = rhs.handle_;
  223|  36.3k|      call_ = rhs.call_;
  224|  36.3k|      rhs.handle_ = nullptr;
  225|  36.3k|    }
  226|  59.5k|  }
AsyncEpollHelloWorld.cpp:_ZN5ofats13any_invocableIFvvEEC2IZZ4testvENK3$_0clIN3uWS12HttpResponseILb0EEENS6_11HttpRequestEEEDaPT_PT0_EUlvE_vEEOSA_:
  303|  23.2k|    any_invocable(F&& f) {                                                     \
  304|  23.2k|      base_type::template create<std::decay_t<F>>(std::forward<F>(f));         \
  305|  23.2k|    }                                                                          \
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJEE6createIZZ4testvENK3$_0clIN3uWS12HttpResponseILb0EEENS6_11HttpRequestEEEDaPT_PT0_EUlvE_JSE_EEEvDpOT0_:
  232|  23.2k|  void create(Args&&... args) {
  233|  23.2k|    using hdl = handler<F>;
  234|  23.2k|    hdl::create(storage_, std::forward<Args>(args)...);
  235|  23.2k|    handle_ = &hdl::handle;
  236|  23.2k|    call_ = &hdl::call;
  237|  23.2k|  }
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE13small_handlerIZZ4testvENK3$_0clIN3uWS12HttpResponseILb0EEENS6_11HttpRequestEEEDaPT_PT0_EUlvE_E6createIJSE_EEEvRNS0_7storageEDpOT_:
  118|  82.8k|    static void create(storage& s, Args&&... args) {
  119|  82.8k|      new (static_cast<void*>(&s.buf_)) T(std::forward<Args>(args)...);
  120|  82.8k|    }
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE12handler_baseINS2_13small_handlerIZZ4testvENK3$_0clIN3uWS12HttpResponseILb0EEENS7_11HttpRequestEEEDaPT_PT0_EUlvE_EEE6handleENS0_6actionEPNS0_7storageESK_:
  103|  82.8k|    static void handle(action act, storage* current, storage* other = nullptr) {
  104|  82.8k|      switch (act) {
  ------------------
  |  Branch (104:15): [True: 0, False: 82.8k]
  ------------------
  105|  23.2k|        case (action::destroy):
  ------------------
  |  Branch (105:9): [True: 23.2k, False: 59.5k]
  ------------------
  106|  23.2k|          Derived::destroy(*current);
  107|  23.2k|          break;
  108|  59.5k|        case (action::move):
  ------------------
  |  Branch (108:9): [True: 59.5k, False: 23.2k]
  ------------------
  109|  59.5k|          Derived::move(*current, *other);
  110|  59.5k|          break;
  111|  82.8k|      }
  112|  82.8k|    }
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE13small_handlerIZZ4testvENK3$_0clIN3uWS12HttpResponseILb0EEENS6_11HttpRequestEEEDaPT_PT0_EUlvE_E7destroyERNS0_7storageE:
  122|  82.8k|    static void destroy(storage& s) noexcept {
  123|  82.8k|      T& value = *static_cast<T*>(static_cast<void*>(&s.buf_));
  124|  82.8k|      value.~T();
  125|  82.8k|    }
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE13small_handlerIZZ4testvENK3$_0clIN3uWS12HttpResponseILb0EEENS6_11HttpRequestEEEDaPT_PT0_EUlvE_E4moveERNS0_7storageESH_:
  127|  59.5k|    static void move(storage& dst, storage& src) noexcept {
  128|  59.5k|      create(dst, std::move(*static_cast<T*>(static_cast<void*>(&src.buf_))));
  129|  59.5k|      destroy(src);
  130|  59.5k|    }
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE13small_handlerIZZ4testvENK3$_0clIN3uWS12HttpResponseILb0EEENS6_11HttpRequestEEEDaPT_PT0_EUlvE_E4callERNS0_7storageE:
  132|  10.1k|    static R call(storage& s, ArgTypes... args) {
  133|  10.1k|      return std::invoke(*static_cast<T*>(static_cast<void*>(&s.buf_)),
  134|  10.1k|                         std::forward<ArgTypes>(args)...);
  135|  10.1k|    }
AsyncEpollHelloWorld.cpp:_ZN5ofats13any_invocableIFvvEEC2IZZ4testvENK3$_0clIN3uWS12HttpResponseILb0EEENS6_11HttpRequestEEEDaPT_PT0_EUlvE0_vEEOSA_:
  303|  23.2k|    any_invocable(F&& f) {                                                     \
  304|  23.2k|      base_type::template create<std::decay_t<F>>(std::forward<F>(f));         \
  305|  23.2k|    }                                                                          \
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJEE6createIZZ4testvENK3$_0clIN3uWS12HttpResponseILb0EEENS6_11HttpRequestEEEDaPT_PT0_EUlvE0_JSE_EEEvDpOT0_:
  232|  23.2k|  void create(Args&&... args) {
  233|  23.2k|    using hdl = handler<F>;
  234|  23.2k|    hdl::create(storage_, std::forward<Args>(args)...);
  235|  23.2k|    handle_ = &hdl::handle;
  236|  23.2k|    call_ = &hdl::call;
  237|  23.2k|  }
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE13large_handlerIZZ4testvENK3$_0clIN3uWS12HttpResponseILb0EEENS6_11HttpRequestEEEDaPT_PT0_EUlvE0_E6createIJSE_EEEvRNS0_7storageEDpOT_:
  141|  23.2k|    static void create(storage& s, Args&&... args) {
  142|  23.2k|      s.ptr_ = new T(std::forward<Args>(args)...);
  143|  23.2k|    }
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE12handler_baseINS2_13large_handlerIZZ4testvENK3$_0clIN3uWS12HttpResponseILb0EEENS7_11HttpRequestEEEDaPT_PT0_EUlvE0_EEE6handleENS0_6actionEPNS0_7storageESK_:
  103|  50.4k|    static void handle(action act, storage* current, storage* other = nullptr) {
  104|  50.4k|      switch (act) {
  ------------------
  |  Branch (104:15): [True: 0, False: 50.4k]
  ------------------
  105|  23.2k|        case (action::destroy):
  ------------------
  |  Branch (105:9): [True: 23.2k, False: 27.2k]
  ------------------
  106|  23.2k|          Derived::destroy(*current);
  107|  23.2k|          break;
  108|  27.2k|        case (action::move):
  ------------------
  |  Branch (108:9): [True: 27.2k, False: 23.2k]
  ------------------
  109|  27.2k|          Derived::move(*current, *other);
  110|  27.2k|          break;
  111|  50.4k|      }
  112|  50.4k|    }
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE13large_handlerIZZ4testvENK3$_0clIN3uWS12HttpResponseILb0EEENS6_11HttpRequestEEEDaPT_PT0_EUlvE0_E7destroyERNS0_7storageE:
  145|  23.2k|    static void destroy(storage& s) noexcept { delete static_cast<T*>(s.ptr_); }
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE13large_handlerIZZ4testvENK3$_0clIN3uWS12HttpResponseILb0EEENS6_11HttpRequestEEEDaPT_PT0_EUlvE0_E4moveERNS0_7storageESH_:
  147|  27.2k|    static void move(storage& dst, storage& src) noexcept {
  148|  27.2k|      dst.ptr_ = src.ptr_;
  149|  27.2k|    }
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE13large_handlerIZZ4testvENK3$_0clIN3uWS12HttpResponseILb0EEENS6_11HttpRequestEEEDaPT_PT0_EUlvE0_E4callERNS0_7storageE:
  151|  22.6k|    static R call(storage& s, ArgTypes... args) {
  152|  22.6k|      return std::invoke(*static_cast<T*>(s.ptr_),
  153|  22.6k|                         std::forward<ArgTypes>(args)...);
  154|  22.6k|    }
AsyncEpollHelloWorld.cpp:_ZN5ofats13any_invocableIFvvEEC2IZZZ4testvENK3$_0clIN3uWS12HttpResponseILb0EEENS6_11HttpRequestEEEDaPT_PT0_ENKUlvE0_clEvEUlvE_vEEOSA_:
  303|  13.0k|    any_invocable(F&& f) {                                                     \
  304|  13.0k|      base_type::template create<std::decay_t<F>>(std::forward<F>(f));         \
  305|  13.0k|    }                                                                          \
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJEE6createIZZZ4testvENK3$_0clIN3uWS12HttpResponseILb0EEENS6_11HttpRequestEEEDaPT_PT0_ENKUlvE0_clEvEUlvE_JSF_EEEvDpOT0_:
  232|  13.0k|  void create(Args&&... args) {
  233|  13.0k|    using hdl = handler<F>;
  234|  13.0k|    hdl::create(storage_, std::forward<Args>(args)...);
  235|  13.0k|    handle_ = &hdl::handle;
  236|  13.0k|    call_ = &hdl::call;
  237|  13.0k|  }
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE13large_handlerIZZZ4testvENK3$_0clIN3uWS12HttpResponseILb0EEENS6_11HttpRequestEEEDaPT_PT0_ENKUlvE0_clEvEUlvE_E6createIJSF_EEEvRNS0_7storageEDpOT_:
  141|  13.0k|    static void create(storage& s, Args&&... args) {
  142|  13.0k|      s.ptr_ = new T(std::forward<Args>(args)...);
  143|  13.0k|    }
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE12handler_baseINS2_13large_handlerIZZZ4testvENK3$_0clIN3uWS12HttpResponseILb0EEENS7_11HttpRequestEEEDaPT_PT0_ENKUlvE0_clEvEUlvE_EEE6handleENS0_6actionEPNS0_7storageESL_:
  103|  13.0k|    static void handle(action act, storage* current, storage* other = nullptr) {
  104|  13.0k|      switch (act) {
  ------------------
  |  Branch (104:15): [True: 0, False: 13.0k]
  ------------------
  105|  13.0k|        case (action::destroy):
  ------------------
  |  Branch (105:9): [True: 13.0k, False: 0]
  ------------------
  106|  13.0k|          Derived::destroy(*current);
  107|  13.0k|          break;
  108|      0|        case (action::move):
  ------------------
  |  Branch (108:9): [True: 0, False: 13.0k]
  ------------------
  109|      0|          Derived::move(*current, *other);
  110|      0|          break;
  111|  13.0k|      }
  112|  13.0k|    }
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE13large_handlerIZZZ4testvENK3$_0clIN3uWS12HttpResponseILb0EEENS6_11HttpRequestEEEDaPT_PT0_ENKUlvE0_clEvEUlvE_E7destroyERNS0_7storageE:
  145|  13.0k|    static void destroy(storage& s) noexcept { delete static_cast<T*>(s.ptr_); }
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE13large_handlerIZZZ4testvENK3$_0clIN3uWS12HttpResponseILb0EEENS6_11HttpRequestEEEDaPT_PT0_ENKUlvE0_clEvEUlvE_E4callERNS0_7storageE:
  151|  13.0k|    static R call(storage& s, ArgTypes... args) {
  152|  13.0k|      return std::invoke(*static_cast<T*>(s.ptr_),
  153|  13.0k|                         std::forward<ArgTypes>(args)...);
  154|  13.0k|    }
_ZN5ofats13any_invocableIFvvEEaSIDnDnEENSt3__19enable_ifIXaantsr3stdE9is_same_vIT0_S2_Esr3stdE23is_move_constructible_vIS6_EERS2_E4typeEOT_:
  335|  13.0k|    operator=(F&& f) {                                                         \
  336|  13.0k|      any_invocable{std::forward<F>(f)}.swap(*this);                           \
  337|  13.0k|      return *this;                                                            \
  338|  13.0k|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIvLb0EJEEC2EDn:
  187|  13.0k|  any_invocable_impl(std::nullptr_t) noexcept {}
_ZN5ofats13any_invocableIFbmEEaSIDnDnEENSt3__19enable_ifIXaantsr3stdE9is_same_vIT0_S2_Esr3stdE23is_move_constructible_vIS6_EERS2_E4typeEOT_:
  335|  13.0k|    operator=(F&& f) {                                                         \
  336|  13.0k|      any_invocable{std::forward<F>(f)}.swap(*this);                           \
  337|  13.0k|      return *this;                                                            \
  338|  13.0k|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIbLb0EJmEEC2EDn:
  187|  13.0k|  any_invocable_impl(std::nullptr_t) noexcept {}
_ZN5ofats13any_invocableIFvP18us_listen_socket_tEEclES2_:
  345|  1.65k|    R operator()(ArgTypes... args) cv ref noexcept(noex) {                     \
  346|  1.65k|      return base_type::call(std::forward<ArgTypes>(args)...);                 \
  347|  1.65k|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIvLb0EJP18us_listen_socket_tEE4callES3_:
  246|  1.65k|  R call(ArgTypes... args) noexcept(is_noexcept) {
  247|  1.65k|    return call_(storage_, std::forward<ArgTypes>(args)...);
  248|  1.65k|  }
AsyncEpollHelloWorld.cpp:_ZN5ofats13any_invocableIFvP18us_listen_socket_tEEC2IZ4testvE3$_1vEEOT_:
  303|  1.65k|    any_invocable(F&& f) {                                                     \
  304|  1.65k|      base_type::template create<std::decay_t<F>>(std::forward<F>(f));         \
  305|  1.65k|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIvLb0EJP18us_listen_socket_tEEC2Ev:
  186|  1.65k|  any_invocable_impl() noexcept = default;
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJP18us_listen_socket_tEE6createIZ4testvE3$_1JS6_EEEvDpOT0_:
  232|  1.65k|  void create(Args&&... args) {
  233|  1.65k|    using hdl = handler<F>;
  234|  1.65k|    hdl::create(storage_, std::forward<Args>(args)...);
  235|  1.65k|    handle_ = &hdl::handle;
  236|  1.65k|    call_ = &hdl::call;
  237|  1.65k|  }
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail14handler_traitsIvJP18us_listen_socket_tEE13small_handlerIZ4testvE3$_1E6createIJS6_EEEvRNS0_7storageEDpOT_:
  118|  1.65k|    static void create(storage& s, Args&&... args) {
  119|  1.65k|      new (static_cast<void*>(&s.buf_)) T(std::forward<Args>(args)...);
  120|  1.65k|    }
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail14handler_traitsIvJP18us_listen_socket_tEE12handler_baseINS4_13small_handlerIZ4testvE3$_1EEE6handleENS0_6actionEPNS0_7storageESC_:
  103|  1.65k|    static void handle(action act, storage* current, storage* other = nullptr) {
  104|  1.65k|      switch (act) {
  ------------------
  |  Branch (104:15): [True: 0, False: 1.65k]
  ------------------
  105|  1.65k|        case (action::destroy):
  ------------------
  |  Branch (105:9): [True: 1.65k, False: 0]
  ------------------
  106|  1.65k|          Derived::destroy(*current);
  107|  1.65k|          break;
  108|      0|        case (action::move):
  ------------------
  |  Branch (108:9): [True: 0, False: 1.65k]
  ------------------
  109|      0|          Derived::move(*current, *other);
  110|      0|          break;
  111|  1.65k|      }
  112|  1.65k|    }
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail14handler_traitsIvJP18us_listen_socket_tEE13small_handlerIZ4testvE3$_1E7destroyERNS0_7storageE:
  122|  1.65k|    static void destroy(storage& s) noexcept {
  123|  1.65k|      T& value = *static_cast<T*>(static_cast<void*>(&s.buf_));
  124|  1.65k|      value.~T();
  125|  1.65k|    }
AsyncEpollHelloWorld.cpp:_ZN5ofats10any_detail14handler_traitsIvJP18us_listen_socket_tEE13small_handlerIZ4testvE3$_1E4callERNS0_7storageES3_:
  132|  1.65k|    static R call(storage& s, ArgTypes... args) {
  133|  1.65k|      return std::invoke(*static_cast<T*>(static_cast<void*>(&s.buf_)),
  134|  1.65k|                         std::forward<ArgTypes>(args)...);
  135|  1.65k|    }

_ZN3uWS5utils6u64toaEmPc:
   46|  13.0k|inline int u64toa(uint64_t value, char *dst) {
   47|  13.0k|    char temp[20];
   48|  13.0k|    char *p = temp;
   49|  26.1k|    do {
   50|  26.1k|        *p++ = (char) ((value % 10) + '0');
   51|  26.1k|        value /= 10;
   52|  26.1k|    } while (value > 0);
  ------------------
  |  Branch (52:14): [True: 13.0k, False: 13.0k]
  ------------------
   53|       |
   54|  13.0k|    int ret = (int) (p - temp);
   55|       |
   56|  26.1k|    do {
   57|  26.1k|        *dst++ = *--p;
   58|  26.1k|    } while (p != temp);
  ------------------
  |  Branch (58:14): [True: 13.0k, False: 13.0k]
  ------------------
   59|       |
   60|  13.0k|    return ret;
   61|  13.0k|}

apple_no_sigpipe:
  259|  1.01M|LIBUS_SOCKET_DESCRIPTOR apple_no_sigpipe(LIBUS_SOCKET_DESCRIPTOR fd) {
  260|       |#ifdef __APPLE__
  261|       |    if (fd != LIBUS_SOCKET_ERROR) {
  262|       |        int no_sigpipe = 1;
  263|       |        setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (void *) &no_sigpipe, sizeof(int));
  264|       |    }
  265|       |#endif
  266|  1.01M|    return fd;
  267|  1.01M|}
bsd_set_nonblocking:
  269|  1.01M|LIBUS_SOCKET_DESCRIPTOR bsd_set_nonblocking(LIBUS_SOCKET_DESCRIPTOR fd) {
  270|       |#ifdef _WIN32
  271|       |    /* Libuv will set windows sockets as non-blocking */
  272|       |#else
  273|  1.01M|    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
  274|  1.01M|#endif
  275|  1.01M|    return fd;
  276|  1.01M|}
bsd_socket_nodelay:
  278|  1.01M|void bsd_socket_nodelay(LIBUS_SOCKET_DESCRIPTOR fd, int enabled) {
  279|  1.01M|    setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void *) &enabled, sizeof(enabled));
  280|  1.01M|}
bsd_create_socket:
  290|  1.65k|LIBUS_SOCKET_DESCRIPTOR bsd_create_socket(int domain, int type, int protocol) {
  291|       |    // returns INVALID_SOCKET on error
  292|  1.65k|    int flags = 0;
  293|  1.65k|#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
  294|  1.65k|    flags = SOCK_CLOEXEC | SOCK_NONBLOCK;
  295|  1.65k|#endif
  296|       |
  297|  1.65k|    LIBUS_SOCKET_DESCRIPTOR created_fd = socket(domain, type | flags, protocol);
  ------------------
  |  |   38|  1.65k|#define LIBUS_SOCKET_DESCRIPTOR int
  ------------------
  298|       |
  299|  1.65k|    return bsd_set_nonblocking(apple_no_sigpipe(created_fd));
  300|  1.65k|}
bsd_close_socket:
  302|  1.01M|void bsd_close_socket(LIBUS_SOCKET_DESCRIPTOR fd) {
  303|       |#ifdef _WIN32
  304|       |    closesocket(fd);
  305|       |#else
  306|  1.01M|    close(fd);
  307|  1.01M|#endif
  308|  1.01M|}
bsd_shutdown_socket:
  310|  90.8k|void bsd_shutdown_socket(LIBUS_SOCKET_DESCRIPTOR fd) {
  311|       |#ifdef _WIN32
  312|       |    shutdown(fd, SD_SEND);
  313|       |#else
  314|  90.8k|    shutdown(fd, SHUT_WR);
  315|  90.8k|#endif
  316|  90.8k|}
internal_finalize_bsd_addr:
  326|  1.01M|void internal_finalize_bsd_addr(struct bsd_addr_t *addr) {
  327|       |    // parse, so to speak, the address
  328|  1.01M|    if (addr->mem.ss_family == AF_INET6) {
  ------------------
  |  Branch (328:9): [True: 558k, False: 451k]
  ------------------
  329|   558k|        addr->ip = (char *) &((struct sockaddr_in6 *) addr)->sin6_addr;
  330|   558k|        addr->ip_length = sizeof(struct in6_addr);
  331|   558k|        addr->port = ntohs(((struct sockaddr_in6 *) addr)->sin6_port);
  332|   558k|    } else if (addr->mem.ss_family == AF_INET) {
  ------------------
  |  Branch (332:16): [True: 451k, False: 0]
  ------------------
  333|   451k|        addr->ip = (char *) &((struct sockaddr_in *) addr)->sin_addr;
  334|   451k|        addr->ip_length = sizeof(struct in_addr);
  335|   451k|        addr->port = ntohs(((struct sockaddr_in *) addr)->sin_port);
  336|   451k|    } else {
  337|      0|        addr->ip_length = 0;
  338|      0|        addr->port = -1;
  339|      0|    }
  340|  1.01M|}
bsd_addr_get_ip:
  360|  1.01M|char *bsd_addr_get_ip(struct bsd_addr_t *addr) {
  361|  1.01M|    return addr->ip;
  362|  1.01M|}
bsd_addr_get_ip_length:
  364|  1.01M|int bsd_addr_get_ip_length(struct bsd_addr_t *addr) {
  365|  1.01M|    return addr->ip_length;
  366|  1.01M|}
bsd_accept_socket:
  373|  3.02M|LIBUS_SOCKET_DESCRIPTOR bsd_accept_socket(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd_addr_t *addr) {
  374|  3.02M|    LIBUS_SOCKET_DESCRIPTOR accepted_fd;
  ------------------
  |  |   38|  3.02M|#define LIBUS_SOCKET_DESCRIPTOR int
  ------------------
  375|  3.02M|    addr->len = sizeof(addr->mem);
  376|       |
  377|  3.02M|#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
  378|       |    // Linux, FreeBSD
  379|  3.02M|    accepted_fd = accept4(fd, (struct sockaddr *) addr, &addr->len, SOCK_CLOEXEC | SOCK_NONBLOCK);
  380|       |#else
  381|       |    // Windows, OS X
  382|       |    accepted_fd = accept(fd, (struct sockaddr *) addr, &addr->len);
  383|       |
  384|       |#endif
  385|       |
  386|       |    /* We cannot rely on addr since it is not initialized if failed */
  387|  3.02M|    if (accepted_fd == LIBUS_SOCKET_ERROR) {
  ------------------
  |  |   44|  3.02M|#define LIBUS_SOCKET_ERROR -1
  ------------------
  |  Branch (387:9): [True: 2.01M, False: 1.01M]
  ------------------
  388|  2.01M|        return LIBUS_SOCKET_ERROR;
  ------------------
  |  |   44|  2.01M|#define LIBUS_SOCKET_ERROR -1
  ------------------
  389|  2.01M|    }
  390|       |
  391|  1.01M|    internal_finalize_bsd_addr(addr);
  392|       |
  393|  1.01M|    return bsd_set_nonblocking(apple_no_sigpipe(accepted_fd));
  394|  3.02M|}
bsd_recv:
  396|   160k|int bsd_recv(LIBUS_SOCKET_DESCRIPTOR fd, void *buf, int length, int flags) {
  397|   160k|    return recv(fd, buf, length, flags);
  398|   160k|}
bsd_send:
  426|   141k|int bsd_send(LIBUS_SOCKET_DESCRIPTOR fd, const char *buf, int length, int msg_more) {
  427|       |
  428|       |    // MSG_MORE (Linux), MSG_PARTIAL (Windows), TCP_NOPUSH (BSD)
  429|       |
  430|       |#ifndef MSG_NOSIGNAL
  431|       |#define MSG_NOSIGNAL 0
  432|       |#endif
  433|       |
  434|   141k|#ifdef MSG_MORE
  435|       |
  436|       |    // for Linux we do not want signals
  437|   141k|    return send(fd, buf, length, ((msg_more != 0) * MSG_MORE) | MSG_NOSIGNAL);
  438|       |
  439|       |#else
  440|       |
  441|       |    // use TCP_NOPUSH
  442|       |
  443|       |    return send(fd, buf, length, MSG_NOSIGNAL);
  444|       |
  445|       |#endif
  446|   141k|}
bsd_would_block:
  448|  1.21k|int bsd_would_block() {
  449|       |#ifdef _WIN32
  450|       |    return WSAGetLastError() == WSAEWOULDBLOCK;
  451|       |#else
  452|  1.21k|    return errno == EWOULDBLOCK;// || errno == EAGAIN;
  453|  1.21k|#endif
  454|  1.21k|}
bsd_create_listen_socket:
  458|  1.65k|LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket(const char *host, int port, int options) {
  459|  1.65k|    struct addrinfo hints, *result;
  460|  1.65k|    memset(&hints, 0, sizeof(struct addrinfo));
  461|       |
  462|  1.65k|    hints.ai_flags = AI_PASSIVE;
  463|  1.65k|    hints.ai_family = AF_UNSPEC;
  464|  1.65k|    hints.ai_socktype = SOCK_STREAM;
  465|       |
  466|  1.65k|    char port_string[16];
  467|  1.65k|    snprintf(port_string, 16, "%d", port);
  468|       |
  469|  1.65k|    if (getaddrinfo(host, port_string, &hints, &result)) {
  ------------------
  |  Branch (469:9): [True: 0, False: 1.65k]
  ------------------
  470|      0|        return LIBUS_SOCKET_ERROR;
  ------------------
  |  |   44|      0|#define LIBUS_SOCKET_ERROR -1
  ------------------
  471|      0|    }
  472|       |
  473|  1.65k|    LIBUS_SOCKET_DESCRIPTOR listenFd = LIBUS_SOCKET_ERROR;
  ------------------
  |  |   38|  1.65k|#define LIBUS_SOCKET_DESCRIPTOR int
  ------------------
                  LIBUS_SOCKET_DESCRIPTOR listenFd = LIBUS_SOCKET_ERROR;
  ------------------
  |  |   44|  1.65k|#define LIBUS_SOCKET_ERROR -1
  ------------------
  474|  1.65k|    struct addrinfo *listenAddr;
  475|  3.31k|    for (struct addrinfo *a = result; a && listenFd == LIBUS_SOCKET_ERROR; a = a->ai_next) {
  ------------------
  |  |   44|  1.65k|#define LIBUS_SOCKET_ERROR -1
  ------------------
  |  Branch (475:39): [True: 1.65k, False: 1.65k]
  |  Branch (475:44): [True: 1.65k, False: 0]
  ------------------
  476|  1.65k|        if (a->ai_family == AF_INET6) {
  ------------------
  |  Branch (476:13): [True: 931, False: 724]
  ------------------
  477|    931|            listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol);
  478|    931|            listenAddr = a;
  479|    931|        }
  480|  1.65k|    }
  481|       |
  482|  2.37k|    for (struct addrinfo *a = result; a && listenFd == LIBUS_SOCKET_ERROR; a = a->ai_next) {
  ------------------
  |  |   44|  1.65k|#define LIBUS_SOCKET_ERROR -1
  ------------------
  |  Branch (482:39): [True: 1.65k, False: 724]
  |  Branch (482:44): [True: 724, False: 931]
  ------------------
  483|    724|        if (a->ai_family == AF_INET) {
  ------------------
  |  Branch (483:13): [True: 723, False: 1]
  ------------------
  484|    723|            listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol);
  485|    723|            listenAddr = a;
  486|    723|        }
  487|    724|    }
  488|       |
  489|  1.65k|    if (listenFd == LIBUS_SOCKET_ERROR) {
  ------------------
  |  |   44|  1.65k|#define LIBUS_SOCKET_ERROR -1
  ------------------
  |  Branch (489:9): [True: 1, False: 1.65k]
  ------------------
  490|      1|        freeaddrinfo(result);
  491|      1|        return LIBUS_SOCKET_ERROR;
  ------------------
  |  |   44|      1|#define LIBUS_SOCKET_ERROR -1
  ------------------
  492|      1|    }
  493|       |
  494|  1.65k|    if (port != 0) {
  ------------------
  |  Branch (494:9): [True: 1.65k, False: 0]
  ------------------
  495|       |        /* Otherwise, always enable SO_REUSEPORT and SO_REUSEADDR _unless_ options specify otherwise */
  496|       |#ifdef _WIN32
  497|       |        if (options & LIBUS_LISTEN_EXCLUSIVE_PORT) {
  498|       |            int optval2 = 1;
  499|       |            setsockopt(listenFd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (void *) &optval2, sizeof(optval2));
  500|       |        } else {
  501|       |            int optval3 = 1;
  502|       |            setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, (void *) &optval3, sizeof(optval3));
  503|       |        }
  504|       |#else
  505|  1.65k|    #if /*defined(__linux) &&*/ defined(SO_REUSEPORT)
  506|  1.65k|        if (!(options & LIBUS_LISTEN_EXCLUSIVE_PORT)) {
  ------------------
  |  Branch (506:13): [True: 1.65k, False: 0]
  ------------------
  507|  1.65k|            int optval = 1;
  508|  1.65k|            setsockopt(listenFd, SOL_SOCKET, SO_REUSEPORT, (void *) &optval, sizeof(optval));
  509|  1.65k|        }
  510|  1.65k|    #endif
  511|  1.65k|        int enabled = 1;
  512|  1.65k|        setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, (void *) &enabled, sizeof(enabled));
  513|  1.65k|#endif
  514|       |
  515|  1.65k|    }
  516|       |    
  517|  1.65k|#ifdef IPV6_V6ONLY
  518|  1.65k|    int disabled = 0;
  519|  1.65k|    setsockopt(listenFd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &disabled, sizeof(disabled));
  520|  1.65k|#endif
  521|       |
  522|  1.65k|    if (bind(listenFd, listenAddr->ai_addr, (socklen_t) listenAddr->ai_addrlen) || listen(listenFd, 512)) {
  ------------------
  |  Branch (522:9): [True: 0, False: 1.65k]
  |  Branch (522:84): [True: 11, False: 1.64k]
  ------------------
  523|     11|        bsd_close_socket(listenFd);
  524|     11|        freeaddrinfo(result);
  525|     11|        return LIBUS_SOCKET_ERROR;
  ------------------
  |  |   44|     11|#define LIBUS_SOCKET_ERROR -1
  ------------------
  526|     11|    }
  527|       |
  528|  1.64k|    freeaddrinfo(result);
  529|  1.64k|    return listenFd;
  530|  1.65k|}

default_is_low_prio_handler:
   25|   160k|int default_is_low_prio_handler(struct us_socket_t *s) {
   26|   160k|    return 0;
   27|   160k|}
us_listen_socket_close:
   35|  1.64k|void us_listen_socket_close(int ssl, struct us_listen_socket_t *ls) {
   36|       |    /* us_listen_socket_t extends us_socket_t so we close in similar ways */
   37|  1.64k|    if (!us_socket_is_closed(0, &ls->s)) {
  ------------------
  |  Branch (37:9): [True: 1.64k, False: 0]
  ------------------
   38|  1.64k|        us_internal_socket_context_unlink_listen_socket(ls->s.context, ls);
   39|  1.64k|        us_poll_stop((struct us_poll_t *) &ls->s, ls->s.context->loop);
   40|  1.64k|        bsd_close_socket(us_poll_fd((struct us_poll_t *) &ls->s));
   41|       |
   42|       |        /* Link this socket to the close-list and let it be deleted after this iteration */
   43|  1.64k|        ls->s.next = ls->s.context->loop->data.closed_head;
   44|  1.64k|        ls->s.context->loop->data.closed_head = &ls->s;
   45|       |
   46|       |        /* Any socket with prev = context is marked as closed */
   47|  1.64k|        ls->s.prev = (struct us_socket_t *) ls->s.context;
   48|  1.64k|    }
   49|       |
   50|       |    /* We cannot immediately free a listen socket as we can be inside an accept loop */
   51|  1.64k|}
us_internal_socket_context_unlink_listen_socket:
   71|  1.64k|void us_internal_socket_context_unlink_listen_socket(struct us_socket_context_t *context, struct us_listen_socket_t *ls) {
   72|       |    /* We have to properly update the iterator used to sweep sockets for timeouts */
   73|  1.64k|    if (ls == (struct us_listen_socket_t *) context->iterator) {
  ------------------
  |  Branch (73:9): [True: 0, False: 1.64k]
  ------------------
   74|      0|        context->iterator = ls->s.next;
   75|      0|    }
   76|       |
   77|  1.64k|    if (ls->s.prev == ls->s.next) {
  ------------------
  |  Branch (77:9): [True: 1.64k, False: 0]
  ------------------
   78|  1.64k|        context->head_listen_sockets = 0;
   79|  1.64k|    } else {
   80|      0|        if (ls->s.prev) {
  ------------------
  |  Branch (80:13): [True: 0, False: 0]
  ------------------
   81|      0|            ls->s.prev->next = ls->s.next;
   82|      0|        } else {
   83|      0|            context->head_listen_sockets = (struct us_listen_socket_t *) ls->s.next;
   84|      0|        }
   85|      0|        if (ls->s.next) {
  ------------------
  |  Branch (85:13): [True: 0, False: 0]
  ------------------
   86|      0|            ls->s.next->prev = ls->s.prev;
   87|      0|        }
   88|      0|    }
   89|  1.64k|}
us_internal_socket_context_unlink_socket:
   91|  1.01M|void us_internal_socket_context_unlink_socket(struct us_socket_context_t *context, struct us_socket_t *s) {
   92|       |    /* We have to properly update the iterator used to sweep sockets for timeouts */
   93|  1.01M|    if (s == context->iterator) {
  ------------------
  |  Branch (93:9): [True: 1.79k, False: 1.00M]
  ------------------
   94|  1.79k|        context->iterator = s->next;
   95|  1.79k|    }
   96|       |
   97|  1.01M|    if (s->prev == s->next) {
  ------------------
  |  Branch (97:9): [True: 130k, False: 879k]
  ------------------
   98|   130k|        context->head_sockets = 0;
   99|   879k|    } else {
  100|   879k|        if (s->prev) {
  ------------------
  |  Branch (100:13): [True: 202k, False: 676k]
  ------------------
  101|   202k|            s->prev->next = s->next;
  102|   676k|        } else {
  103|   676k|            context->head_sockets = s->next;
  104|   676k|        }
  105|   879k|        if (s->next) {
  ------------------
  |  Branch (105:13): [True: 859k, False: 19.6k]
  ------------------
  106|   859k|            s->next->prev = s->prev;
  107|   859k|        }
  108|   879k|    }
  109|  1.01M|}
us_internal_socket_context_link_listen_socket:
  112|  1.64k|void us_internal_socket_context_link_listen_socket(struct us_socket_context_t *context, struct us_listen_socket_t *ls) {
  113|  1.64k|    ls->s.context = context;
  114|  1.64k|    ls->s.next = (struct us_socket_t *) context->head_listen_sockets;
  115|  1.64k|    ls->s.prev = 0;
  116|  1.64k|    if (context->head_listen_sockets) {
  ------------------
  |  Branch (116:9): [True: 0, False: 1.64k]
  ------------------
  117|      0|        context->head_listen_sockets->s.prev = &ls->s;
  118|      0|    }
  119|  1.64k|    context->head_listen_sockets = ls;
  120|  1.64k|}
us_internal_socket_context_link_socket:
  123|  1.01M|void us_internal_socket_context_link_socket(struct us_socket_context_t *context, struct us_socket_t *s) {
  124|  1.01M|    s->context = context;
  125|  1.01M|    s->next = context->head_sockets;
  126|  1.01M|    s->prev = 0;
  127|  1.01M|    if (context->head_sockets) {
  ------------------
  |  Branch (127:9): [True: 879k, False: 130k]
  ------------------
  128|   879k|        context->head_sockets->prev = s;
  129|   879k|    }
  130|  1.01M|    context->head_sockets = s;
  131|  1.01M|}
us_socket_context_loop:
  133|   777k|struct us_loop_t *us_socket_context_loop(int ssl, struct us_socket_context_t *context) {
  134|   777k|    return context->loop;
  135|   777k|}
us_create_socket_context:
  204|  1.65k|struct us_socket_context_t *us_create_socket_context(int ssl, struct us_loop_t *loop, int context_ext_size, struct us_socket_context_options_t options) {
  205|       |#ifndef LIBUS_NO_SSL
  206|       |    if (ssl) {
  207|       |        /* This function will call us, again, with SSL = false and a bigger ext_size */
  208|       |        return (struct us_socket_context_t *) us_internal_create_ssl_socket_context(loop, context_ext_size, options);
  209|       |    }
  210|       |#endif
  211|       |
  212|       |    /* This path is taken once either way - always BEFORE whatever SSL may do LATER.
  213|       |     * context_ext_size will however be modified larger in case of SSL, to hold SSL extensions */
  214|       |
  215|  1.65k|    struct us_socket_context_t *context = malloc(sizeof(struct us_socket_context_t) + context_ext_size);
  216|  1.65k|    context->loop = loop;
  217|  1.65k|    context->head_sockets = 0;
  218|  1.65k|    context->head_listen_sockets = 0;
  219|  1.65k|    context->iterator = 0;
  220|  1.65k|    context->next = 0;
  221|  1.65k|    context->is_low_prio = default_is_low_prio_handler;
  222|       |
  223|       |    /* Begin at 0 */
  224|  1.65k|    context->timestamp = 0;
  225|  1.65k|    context->long_timestamp = 0;
  226|  1.65k|    context->global_tick = 0;
  227|       |
  228|  1.65k|    us_internal_loop_link(loop, context);
  229|       |
  230|       |    /* If we are called from within SSL code, SSL code will make further changes to us */
  231|  1.65k|    return context;
  232|  1.65k|}
us_socket_context_free:
  234|  1.65k|void us_socket_context_free(int ssl, struct us_socket_context_t *context) {
  235|       |#ifndef LIBUS_NO_SSL
  236|       |    if (ssl) {
  237|       |        /* This function will call us again with SSL=false */
  238|       |        us_internal_ssl_socket_context_free((struct us_internal_ssl_socket_context_t *) context);
  239|       |        return;
  240|       |    }
  241|       |#endif
  242|       |
  243|       |    /* This path is taken once either way - always AFTER whatever SSL may do BEFORE.
  244|       |     * This is the opposite order compared to when creating the context - SSL code is cleaning up before non-SSL */
  245|       |
  246|  1.65k|    us_internal_loop_unlink(context->loop, context);
  247|  1.65k|    free(context);
  248|  1.65k|}
us_socket_context_listen:
  250|  1.65k|struct us_listen_socket_t *us_socket_context_listen(int ssl, struct us_socket_context_t *context, const char *host, int port, int options, int socket_ext_size) {
  251|       |#ifndef LIBUS_NO_SSL
  252|       |    if (ssl) {
  253|       |        return us_internal_ssl_socket_context_listen((struct us_internal_ssl_socket_context_t *) context, host, port, options, socket_ext_size);
  254|       |    }
  255|       |#endif
  256|       |
  257|  1.65k|    LIBUS_SOCKET_DESCRIPTOR listen_socket_fd = bsd_create_listen_socket(host, port, options);
  ------------------
  |  |   38|  1.65k|#define LIBUS_SOCKET_DESCRIPTOR int
  ------------------
  258|       |
  259|  1.65k|    if (listen_socket_fd == LIBUS_SOCKET_ERROR) {
  ------------------
  |  |   44|  1.65k|#define LIBUS_SOCKET_ERROR -1
  ------------------
  |  Branch (259:9): [True: 12, False: 1.64k]
  ------------------
  260|     12|        return 0;
  261|     12|    }
  262|       |
  263|  1.64k|    struct us_poll_t *p = us_create_poll(context->loop, 0, sizeof(struct us_listen_socket_t));
  264|  1.64k|    us_poll_init(p, listen_socket_fd, POLL_TYPE_SEMI_SOCKET);
  265|  1.64k|    us_poll_start(p, context->loop, LIBUS_SOCKET_READABLE);
  ------------------
  |  |   27|  1.64k|#define LIBUS_SOCKET_READABLE EPOLLIN
  ------------------
  266|       |
  267|  1.64k|    struct us_listen_socket_t *ls = (struct us_listen_socket_t *) p;
  268|       |
  269|  1.64k|    ls->s.context = context;
  270|  1.64k|    ls->s.timeout = 255;
  271|  1.64k|    ls->s.long_timeout = 255;
  272|  1.64k|    ls->s.low_prio_state = 0;
  273|  1.64k|    ls->s.next = 0;
  274|  1.64k|    us_internal_socket_context_link_listen_socket(context, ls);
  275|       |
  276|  1.64k|    ls->socket_ext_size = socket_ext_size;
  277|       |
  278|  1.64k|    return ls;
  279|  1.65k|}
us_socket_context_on_open:
  417|  1.65k|void us_socket_context_on_open(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_open)(struct us_socket_t *s, int is_client, char *ip, int ip_length)) {
  418|       |#ifndef LIBUS_NO_SSL
  419|       |    if (ssl) {
  420|       |        us_internal_ssl_socket_context_on_open((struct us_internal_ssl_socket_context_t *) context, (struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *, int,  char *, int)) on_open);
  421|       |        return;
  422|       |    }
  423|       |#endif
  424|       |
  425|  1.65k|    context->on_open = on_open;
  426|  1.65k|}
us_socket_context_on_close:
  428|  1.65k|void us_socket_context_on_close(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_close)(struct us_socket_t *s, int code, void *reason)) {
  429|       |#ifndef LIBUS_NO_SSL
  430|       |    if (ssl) {
  431|       |        us_internal_ssl_socket_context_on_close((struct us_internal_ssl_socket_context_t *) context, (struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *, int code, void *reason)) on_close);
  432|       |        return;
  433|       |    }
  434|       |#endif
  435|       |
  436|  1.65k|    context->on_close = on_close;
  437|  1.65k|}
us_socket_context_on_data:
  439|  1.65k|void us_socket_context_on_data(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_data)(struct us_socket_t *s, char *data, int length)) {
  440|       |#ifndef LIBUS_NO_SSL
  441|       |    if (ssl) {
  442|       |        us_internal_ssl_socket_context_on_data((struct us_internal_ssl_socket_context_t *) context, (struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *, char *, int)) on_data);
  443|       |        return;
  444|       |    }
  445|       |#endif
  446|       |
  447|  1.65k|    context->on_data = on_data;
  448|  1.65k|}
us_socket_context_on_writable:
  450|  1.65k|void us_socket_context_on_writable(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_writable)(struct us_socket_t *s)) {
  451|       |#ifndef LIBUS_NO_SSL
  452|       |    if (ssl) {
  453|       |        us_internal_ssl_socket_context_on_writable((struct us_internal_ssl_socket_context_t *) context, (struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *)) on_writable);
  454|       |        return;
  455|       |    }
  456|       |#endif
  457|       |
  458|  1.65k|    context->on_writable = on_writable;
  459|  1.65k|}
us_socket_context_on_timeout:
  472|  1.65k|void us_socket_context_on_timeout(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_timeout)(struct us_socket_t *)) {
  473|       |#ifndef LIBUS_NO_SSL
  474|       |    if (ssl) {
  475|       |        us_internal_ssl_socket_context_on_timeout((struct us_internal_ssl_socket_context_t *) context, (struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *)) on_timeout);
  476|       |        return;
  477|       |    }
  478|       |#endif
  479|       |
  480|  1.65k|    context->on_socket_timeout = on_timeout;
  481|  1.65k|}
us_socket_context_on_end:
  483|  1.65k|void us_socket_context_on_end(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_end)(struct us_socket_t *)) {
  484|       |#ifndef LIBUS_NO_SSL
  485|       |    if (ssl) {
  486|       |        us_internal_ssl_socket_context_on_end((struct us_internal_ssl_socket_context_t *) context, (struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *)) on_end);
  487|       |        return;
  488|       |    }
  489|       |#endif
  490|       |
  491|  1.65k|    context->on_end = on_end;
  492|  1.65k|}
us_socket_context_ext:
  505|  2.15M|void *us_socket_context_ext(int ssl, struct us_socket_context_t *context) {
  506|       |#ifndef LIBUS_NO_SSL
  507|       |    if (ssl) {
  508|       |        return us_internal_ssl_socket_context_ext((struct us_internal_ssl_socket_context_t *) context);
  509|       |    }
  510|       |#endif
  511|       |
  512|  2.15M|    return context + 1;
  513|  2.15M|}

us_loop_free:
   36|  1.65k|void us_loop_free(struct us_loop_t *loop) {
   37|  1.65k|    us_internal_loop_data_free(loop);
   38|  1.65k|    close(loop->fd);
   39|  1.65k|    free(loop);
   40|  1.65k|}
us_create_poll:
   43|  1.01M|struct us_poll_t *us_create_poll(struct us_loop_t *loop, int fallthrough, unsigned int ext_size) {
   44|  1.01M|    if (!fallthrough) {
  ------------------
  |  Branch (44:9): [True: 1.01M, False: 4.96k]
  ------------------
   45|  1.01M|        loop->num_polls++;
   46|  1.01M|    }
   47|  1.01M|    return malloc(sizeof(struct us_poll_t) + ext_size);
   48|  1.01M|}
us_poll_free:
   51|  1.01M|void us_poll_free(struct us_poll_t *p, struct us_loop_t *loop) {
   52|  1.01M|    loop->num_polls--;
   53|  1.01M|    free(p);
   54|  1.01M|}
us_poll_init:
   61|  1.01M|void us_poll_init(struct us_poll_t *p, LIBUS_SOCKET_DESCRIPTOR fd, int poll_type) {
   62|  1.01M|    p->state.fd = fd;
   63|  1.01M|    p->state.poll_type = poll_type;
   64|  1.01M|}
us_poll_events:
   66|  12.6M|int us_poll_events(struct us_poll_t *p) {
   67|  12.6M|    return ((p->state.poll_type & POLL_TYPE_POLLING_IN) ? LIBUS_SOCKET_READABLE : 0) | ((p->state.poll_type & POLL_TYPE_POLLING_OUT) ? LIBUS_SOCKET_WRITABLE : 0);
  ------------------
  |  |   27|  12.6M|#define LIBUS_SOCKET_READABLE EPOLLIN
  ------------------
                  return ((p->state.poll_type & POLL_TYPE_POLLING_IN) ? LIBUS_SOCKET_READABLE : 0) | ((p->state.poll_type & POLL_TYPE_POLLING_OUT) ? LIBUS_SOCKET_WRITABLE : 0);
  ------------------
  |  |   28|  12.6M|#define LIBUS_SOCKET_WRITABLE EPOLLOUT
  ------------------
  |  Branch (67:13): [True: 12.6M, False: 26.0k]
  |  Branch (67:89): [True: 245k, False: 12.4M]
  ------------------
   68|  12.6M|}
us_poll_fd:
   70|  10.6M|LIBUS_SOCKET_DESCRIPTOR us_poll_fd(struct us_poll_t *p) {
   71|  10.6M|    return p->state.fd;
   72|  10.6M|}
us_internal_poll_type:
   75|  10.8M|int us_internal_poll_type(struct us_poll_t *p) {
   76|  10.8M|    return p->state.poll_type & 3;
   77|  10.8M|}
us_internal_poll_set_type:
   80|  90.8k|void us_internal_poll_set_type(struct us_poll_t *p, int poll_type) {
   81|  90.8k|    p->state.poll_type = poll_type | (p->state.poll_type & 12);
   82|  90.8k|}
us_timer_ext:
   85|  2.04M|void *us_timer_ext(struct us_timer_t *timer) {
   86|  2.04M|    return ((struct us_internal_callback_t *) timer) + 1;
   87|  2.04M|}
us_create_loop:
   96|  1.65k|struct us_loop_t *us_create_loop(void *hint, void (*wakeup_cb)(struct us_loop_t *loop), void (*pre_cb)(struct us_loop_t *loop), void (*post_cb)(struct us_loop_t *loop), unsigned int ext_size) {
   97|  1.65k|    struct us_loop_t *loop = (struct us_loop_t *) malloc(sizeof(struct us_loop_t) + ext_size);
   98|  1.65k|    loop->num_polls = 0;
   99|       |    /* These could be accessed if we close a poll before starting the loop */
  100|  1.65k|    loop->num_ready_polls = 0;
  101|  1.65k|    loop->current_ready_poll = 0;
  102|       |
  103|  1.65k|#ifdef LIBUS_USE_EPOLL
  104|  1.65k|    loop->fd = epoll_create1(EPOLL_CLOEXEC);
  105|       |#else
  106|       |    loop->fd = kqueue();
  107|       |#endif
  108|       |
  109|  1.65k|    us_internal_loop_data_init(loop, wakeup_cb, pre_cb, post_cb);
  110|  1.65k|    return loop;
  111|  1.65k|}
us_loop_run:
  113|  1.65k|void us_loop_run(struct us_loop_t *loop) {
  114|  1.65k|    us_loop_integrate(loop);
  115|       |
  116|       |    /* While we have non-fallthrough polls we shouldn't fall through */
  117|  2.55M|    while (loop->num_polls) {
  ------------------
  |  Branch (117:12): [True: 2.55M, False: 1.65k]
  ------------------
  118|       |        /* Emit pre callback */
  119|  2.55M|        us_internal_loop_pre(loop);
  120|       |
  121|       |        /* Fetch ready polls */
  122|  2.55M|#ifdef LIBUS_USE_EPOLL
  123|  2.55M|        loop->num_ready_polls = epoll_wait(loop->fd, loop->ready_polls, 1024, -1);
  124|       |#else
  125|       |        loop->num_ready_polls = kevent(loop->fd, NULL, 0, loop->ready_polls, 1024, NULL);
  126|       |#endif
  127|       |
  128|       |        /* Iterate ready polls, dispatching them by type */
  129|  11.7M|        for (loop->current_ready_poll = 0; loop->current_ready_poll < loop->num_ready_polls; loop->current_ready_poll++) {
  ------------------
  |  Branch (129:44): [True: 9.24M, False: 2.55M]
  ------------------
  130|  9.24M|            struct us_poll_t *poll = GET_READY_POLL(loop, loop->current_ready_poll);
  ------------------
  |  |   28|  9.24M|#define GET_READY_POLL(loop, index) (struct us_poll_t *) loop->ready_polls[index].data.ptr
  ------------------
  131|       |            /* Any ready poll marked with nullptr will be ignored */
  132|  9.24M|            if (poll) {
  ------------------
  |  Branch (132:17): [True: 9.24M, False: 0]
  ------------------
  133|  9.24M|#ifdef LIBUS_USE_EPOLL
  134|  9.24M|                int events = loop->ready_polls[loop->current_ready_poll].events;
  135|  9.24M|                int error = loop->ready_polls[loop->current_ready_poll].events & (EPOLLERR | EPOLLHUP);
  136|       |#else
  137|       |                /* EVFILT_READ, EVFILT_TIME, EVFILT_USER are all mapped to LIBUS_SOCKET_READABLE */
  138|       |                int events = LIBUS_SOCKET_READABLE;
  139|       |                if (loop->ready_polls[loop->current_ready_poll].filter == EVFILT_WRITE) {
  140|       |                    events = LIBUS_SOCKET_WRITABLE;
  141|       |                }
  142|       |                int error = loop->ready_polls[loop->current_ready_poll].flags & (EV_ERROR | EV_EOF);
  143|       |#endif
  144|       |                /* Always filter all polls by what they actually poll for (callback polls always poll for readable) */
  145|  9.24M|                events &= us_poll_events(poll);
  146|  9.24M|                if (events || error) {
  ------------------
  |  Branch (146:21): [True: 6.34M, False: 2.90M]
  |  Branch (146:31): [True: 2.90M, False: 0]
  ------------------
  147|  9.24M|                    us_internal_dispatch_ready_poll(poll, error, events);
  148|  9.24M|                }
  149|  9.24M|            }
  150|  9.24M|        }
  151|       |        /* Emit post callback */
  152|  2.55M|        us_internal_loop_post(loop);
  153|  2.55M|    }
  154|  1.65k|}
us_internal_loop_update_pending_ready_polls:
  156|  1.01M|void us_internal_loop_update_pending_ready_polls(struct us_loop_t *loop, struct us_poll_t *old_poll, struct us_poll_t *new_poll, int old_events, int new_events) {
  157|  1.01M|#ifdef LIBUS_USE_EPOLL
  158|       |    /* Epoll only has one ready poll per poll */
  159|  1.01M|    int num_entries_possibly_remaining = 1;
  160|       |#else
  161|       |    /* Ready polls may contain same poll twice under kqueue, as one poll may hold two filters */
  162|       |    int num_entries_possibly_remaining = 2;//((old_events & LIBUS_SOCKET_READABLE) ? 1 : 0) + ((old_events & LIBUS_SOCKET_WRITABLE) ? 1 : 0);
  163|       |#endif
  164|       |
  165|       |    /* Todo: for kqueue if we track things in us_change_poll it is possible to have a fast path with no seeking in cases of:
  166|       |    * current poll being us AND we only poll for one thing */
  167|       |
  168|  2.03M|    for (int i = loop->current_ready_poll; i < loop->num_ready_polls && num_entries_possibly_remaining; i++) {
  ------------------
  |  Branch (168:44): [True: 2.01M, False: 19.8k]
  |  Branch (168:73): [True: 1.01M, False: 996k]
  ------------------
  169|  1.01M|        if (GET_READY_POLL(loop, i) == old_poll) {
  ------------------
  |  |   28|  1.01M|#define GET_READY_POLL(loop, index) (struct us_poll_t *) loop->ready_polls[index].data.ptr
  ------------------
  |  Branch (169:13): [True: 1.00M, False: 5.32k]
  ------------------
  170|       |
  171|       |            // if new events does not contain the ready events of this poll then remove (no we filter that out later on)
  172|  1.00M|            SET_READY_POLL(loop, i, new_poll);
  ------------------
  |  |   29|  1.00M|#define SET_READY_POLL(loop, index, poll) loop->ready_polls[index].data.ptr = poll
  ------------------
  173|       |
  174|  1.00M|            num_entries_possibly_remaining--;
  175|  1.00M|        }
  176|  1.01M|    }
  177|  1.01M|}
us_poll_start:
  226|  1.01M|void us_poll_start(struct us_poll_t *p, struct us_loop_t *loop, int events) {
  227|  1.01M|    p->state.poll_type = us_internal_poll_type(p) | ((events & LIBUS_SOCKET_READABLE) ? POLL_TYPE_POLLING_IN : 0) | ((events & LIBUS_SOCKET_WRITABLE) ? POLL_TYPE_POLLING_OUT : 0);
  ------------------
  |  |   27|  1.01M|#define LIBUS_SOCKET_READABLE EPOLLIN
  ------------------
                  p->state.poll_type = us_internal_poll_type(p) | ((events & LIBUS_SOCKET_READABLE) ? POLL_TYPE_POLLING_IN : 0) | ((events & LIBUS_SOCKET_WRITABLE) ? POLL_TYPE_POLLING_OUT : 0);
  ------------------
  |  |   28|  1.01M|#define LIBUS_SOCKET_WRITABLE EPOLLOUT
  ------------------
  |  Branch (227:54): [True: 1.01M, False: 0]
  |  Branch (227:118): [True: 0, False: 1.01M]
  ------------------
  228|       |
  229|  1.01M|#ifdef LIBUS_USE_EPOLL
  230|  1.01M|    struct epoll_event event;
  231|  1.01M|    event.events = events;
  232|  1.01M|    event.data.ptr = p;
  233|  1.01M|    epoll_ctl(loop->fd, EPOLL_CTL_ADD, p->state.fd, &event);
  234|       |#else
  235|       |    kqueue_change(loop->fd, p->state.fd, 0, events, p);
  236|       |#endif
  237|  1.01M|}
us_poll_change:
  239|   250k|void us_poll_change(struct us_poll_t *p, struct us_loop_t *loop, int events) {
  240|   250k|    int old_events = us_poll_events(p);
  241|   250k|    if (old_events != events) {
  ------------------
  |  Branch (241:9): [True: 205k, False: 44.1k]
  ------------------
  242|       |
  243|   205k|        p->state.poll_type = us_internal_poll_type(p) | ((events & LIBUS_SOCKET_READABLE) ? POLL_TYPE_POLLING_IN : 0) | ((events & LIBUS_SOCKET_WRITABLE) ? POLL_TYPE_POLLING_OUT : 0);
  ------------------
  |  |   27|   205k|#define LIBUS_SOCKET_READABLE EPOLLIN
  ------------------
                      p->state.poll_type = us_internal_poll_type(p) | ((events & LIBUS_SOCKET_READABLE) ? POLL_TYPE_POLLING_IN : 0) | ((events & LIBUS_SOCKET_WRITABLE) ? POLL_TYPE_POLLING_OUT : 0);
  ------------------
  |  |   28|   205k|#define LIBUS_SOCKET_WRITABLE EPOLLOUT
  ------------------
  |  Branch (243:58): [True: 179k, False: 26.0k]
  |  Branch (243:122): [True: 92.3k, False: 113k]
  ------------------
  244|       |
  245|   205k|#ifdef LIBUS_USE_EPOLL
  246|   205k|        struct epoll_event event;
  247|   205k|        event.events = events;
  248|   205k|        event.data.ptr = p;
  249|   205k|        epoll_ctl(loop->fd, EPOLL_CTL_MOD, p->state.fd, &event);
  250|       |#else
  251|       |        kqueue_change(loop->fd, p->state.fd, old_events, events, p);
  252|       |#endif
  253|       |        /* Set all removed events to null-polls in pending ready poll list */
  254|       |        //us_internal_loop_update_pending_ready_polls(loop, p, p, old_events, events);
  255|   205k|    }
  256|   250k|}
us_poll_stop:
  258|  1.01M|void us_poll_stop(struct us_poll_t *p, struct us_loop_t *loop) {
  259|  1.01M|    int old_events = us_poll_events(p);
  260|  1.01M|    int new_events = 0;
  261|  1.01M|#ifdef LIBUS_USE_EPOLL
  262|  1.01M|    struct epoll_event event;
  263|  1.01M|    epoll_ctl(loop->fd, EPOLL_CTL_DEL, p->state.fd, &event);
  264|       |#else
  265|       |    if (old_events) {
  266|       |        kqueue_change(loop->fd, p->state.fd, old_events, new_events, NULL);
  267|       |    }
  268|       |#endif
  269|       |
  270|       |    /* Disable any instance of us in the pending ready poll list */
  271|  1.01M|    us_internal_loop_update_pending_ready_polls(loop, p, 0, old_events, new_events);
  272|  1.01M|}
us_internal_accept_poll_event:
  274|  6.17M|unsigned int us_internal_accept_poll_event(struct us_poll_t *p) {
  275|  6.17M|#ifdef LIBUS_USE_EPOLL
  276|  6.17M|    int fd = us_poll_fd(p);
  277|  6.17M|    uint64_t buf;
  278|  6.17M|    int read_length = read(fd, &buf, 8);
  279|  6.17M|    (void)read_length;
  280|  6.17M|    return buf;
  281|       |#else
  282|       |    /* Kqueue has no underlying FD for timers or user events */
  283|       |    return 0;
  284|       |#endif
  285|  6.17M|}
us_create_timer:
  289|  3.31k|struct us_timer_t *us_create_timer(struct us_loop_t *loop, int fallthrough, unsigned int ext_size) {
  290|  3.31k|    struct us_poll_t *p = us_create_poll(loop, fallthrough, sizeof(struct us_internal_callback_t) + ext_size);
  291|  3.31k|    int timerfd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK | TFD_CLOEXEC);
  292|  3.31k|    if (timerfd == -1) {
  ------------------
  |  Branch (292:9): [True: 0, False: 3.31k]
  ------------------
  293|      0|      return NULL;
  294|      0|    }
  295|  3.31k|    us_poll_init(p, timerfd, POLL_TYPE_CALLBACK);
  296|       |
  297|  3.31k|    struct us_internal_callback_t *cb = (struct us_internal_callback_t *) p;
  298|  3.31k|    cb->loop = loop;
  299|  3.31k|    cb->cb_expects_the_loop = 0;
  300|  3.31k|    cb->leave_poll_ready = 0;
  301|       |
  302|  3.31k|    return (struct us_timer_t *) cb;
  303|  3.31k|}
us_timer_close:
  325|  3.31k|void us_timer_close(struct us_timer_t *timer) {
  326|  3.31k|    struct us_internal_callback_t *cb = (struct us_internal_callback_t *) timer;
  327|       |
  328|  3.31k|    us_poll_stop(&cb->p, cb->loop);
  329|  3.31k|    close(us_poll_fd(&cb->p));
  330|       |
  331|       |    /* (regular) sockets are the only polls which are not freed immediately */
  332|  3.31k|    us_poll_free((struct us_poll_t *) timer, cb->loop);
  333|  3.31k|}
us_timer_set:
  335|  3.31k|void us_timer_set(struct us_timer_t *t, void (*cb)(struct us_timer_t *t), int ms, int repeat_ms) {
  336|  3.31k|    struct us_internal_callback_t *internal_cb = (struct us_internal_callback_t *) t;
  337|       |
  338|  3.31k|    internal_cb->cb = (void (*)(struct us_internal_callback_t *)) cb;
  339|       |
  340|  3.31k|    struct itimerspec timer_spec = {
  341|  3.31k|        {repeat_ms / 1000, (long) (repeat_ms % 1000) * (long) 1000000},
  342|  3.31k|        {ms / 1000, (long) (ms % 1000) * (long) 1000000}
  343|  3.31k|    };
  344|       |
  345|  3.31k|    timerfd_settime(us_poll_fd((struct us_poll_t *) t), 0, &timer_spec, NULL);
  346|  3.31k|    us_poll_start((struct us_poll_t *) t, internal_cb->loop, LIBUS_SOCKET_READABLE);
  ------------------
  |  |   27|  3.31k|#define LIBUS_SOCKET_READABLE EPOLLIN
  ------------------
  347|  3.31k|}
us_internal_create_async:
  374|  1.65k|struct us_internal_async *us_internal_create_async(struct us_loop_t *loop, int fallthrough, unsigned int ext_size) {
  375|  1.65k|    struct us_poll_t *p = us_create_poll(loop, fallthrough, sizeof(struct us_internal_callback_t) + ext_size);
  376|  1.65k|    us_poll_init(p, eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC), POLL_TYPE_CALLBACK);
  377|       |
  378|  1.65k|    struct us_internal_callback_t *cb = (struct us_internal_callback_t *) p;
  379|  1.65k|    cb->loop = loop;
  380|  1.65k|    cb->cb_expects_the_loop = 1;
  381|  1.65k|    cb->leave_poll_ready = 0;
  382|       |
  383|  1.65k|    return (struct us_internal_async *) cb;
  384|  1.65k|}
us_internal_async_close:
  387|  1.65k|void us_internal_async_close(struct us_internal_async *a) {
  388|  1.65k|    struct us_internal_callback_t *cb = (struct us_internal_callback_t *) a;
  389|       |
  390|  1.65k|    us_poll_stop(&cb->p, cb->loop);
  391|  1.65k|    close(us_poll_fd(&cb->p));
  392|       |
  393|       |    /* (regular) sockets are the only polls which are not freed immediately */
  394|  1.65k|    us_poll_free((struct us_poll_t *) a, cb->loop);
  395|  1.65k|}
us_internal_async_set:
  397|  1.65k|void us_internal_async_set(struct us_internal_async *a, void (*cb)(struct us_internal_async *)) {
  398|  1.65k|    struct us_internal_callback_t *internal_cb = (struct us_internal_callback_t *) a;
  399|       |
  400|  1.65k|    internal_cb->cb = (void (*)(struct us_internal_callback_t *)) cb;
  401|       |
  402|  1.65k|    us_poll_start((struct us_poll_t *) a, internal_cb->loop, LIBUS_SOCKET_READABLE);
  ------------------
  |  |   27|  1.65k|#define LIBUS_SOCKET_READABLE EPOLLIN
  ------------------
  403|  1.65k|}
us_internal_async_wakeup:
  405|  23.2k|void us_internal_async_wakeup(struct us_internal_async *a) {
  406|  23.2k|    uint64_t one = 1;
  407|  23.2k|    int written = write(us_poll_fd((struct us_poll_t *) a), &one, 8);
  408|  23.2k|    (void)written;
  409|  23.2k|}

us_internal_loop_data_init:
   26|  1.65k|    void (*pre_cb)(struct us_loop_t *loop), void (*post_cb)(struct us_loop_t *loop)) {
   27|  1.65k|    loop->data.sweep_timer = us_create_timer(loop, 1, 0);
   28|  1.65k|    loop->data.recv_buf = malloc(LIBUS_RECV_BUFFER_LENGTH + LIBUS_RECV_BUFFER_PADDING * 2);
  ------------------
  |  |   22|  1.65k|#define LIBUS_RECV_BUFFER_LENGTH 524288
  ------------------
                  loop->data.recv_buf = malloc(LIBUS_RECV_BUFFER_LENGTH + LIBUS_RECV_BUFFER_PADDING * 2);
  ------------------
  |  |   26|  1.65k|#define LIBUS_RECV_BUFFER_PADDING 32
  ------------------
   29|  1.65k|    loop->data.ssl_data = 0;
   30|  1.65k|    loop->data.head = 0;
   31|  1.65k|    loop->data.iterator = 0;
   32|  1.65k|    loop->data.closed_head = 0;
   33|  1.65k|    loop->data.low_prio_head = 0;
   34|  1.65k|    loop->data.low_prio_budget = 0;
   35|       |
   36|  1.65k|    loop->data.pre_cb = pre_cb;
   37|  1.65k|    loop->data.post_cb = post_cb;
   38|  1.65k|    loop->data.iteration_nr = 0;
   39|       |
   40|  1.65k|    loop->data.wakeup_async = us_internal_create_async(loop, 1, 0);
   41|  1.65k|    us_internal_async_set(loop->data.wakeup_async, (void (*)(struct us_internal_async *)) wakeup_cb);
   42|  1.65k|}
us_internal_loop_data_free:
   44|  1.65k|void us_internal_loop_data_free(struct us_loop_t *loop) {
   45|       |#ifndef LIBUS_NO_SSL
   46|       |    us_internal_free_loop_ssl_data(loop);
   47|       |#endif
   48|       |
   49|  1.65k|    free(loop->data.recv_buf);
   50|       |
   51|  1.65k|    us_timer_close(loop->data.sweep_timer);
   52|  1.65k|    us_internal_async_close(loop->data.wakeup_async);
   53|  1.65k|}
us_wakeup_loop:
   55|  23.2k|void us_wakeup_loop(struct us_loop_t *loop) {
   56|  23.2k|    us_internal_async_wakeup(loop->data.wakeup_async);
   57|  23.2k|}
us_internal_loop_link:
   59|  1.65k|void us_internal_loop_link(struct us_loop_t *loop, struct us_socket_context_t *context) {
   60|       |    /* Insert this context as the head of loop */
   61|  1.65k|    context->next = loop->data.head;
   62|  1.65k|    context->prev = 0;
   63|  1.65k|    if (loop->data.head) {
  ------------------
  |  Branch (63:9): [True: 0, False: 1.65k]
  ------------------
   64|      0|        loop->data.head->prev = context;
   65|      0|    }
   66|  1.65k|    loop->data.head = context;
   67|  1.65k|}
us_internal_loop_unlink:
   70|  1.65k|void us_internal_loop_unlink(struct us_loop_t *loop, struct us_socket_context_t *context) {
   71|  1.65k|    if (loop->data.head == context) {
  ------------------
  |  Branch (71:9): [True: 1.65k, False: 0]
  ------------------
   72|  1.65k|        loop->data.head = context->next;
   73|  1.65k|        if (loop->data.head) {
  ------------------
  |  Branch (73:13): [True: 0, False: 1.65k]
  ------------------
   74|      0|            loop->data.head->prev = 0;
   75|      0|        }
   76|  1.65k|    } else {
   77|      0|        context->prev->next = context->next;
   78|      0|        if (context->next) {
  ------------------
  |  Branch (78:13): [True: 0, False: 0]
  ------------------
   79|      0|            context->next->prev = context->prev;
   80|      0|        }
   81|      0|    }
   82|  1.65k|}
us_internal_timer_sweep:
   85|  2.08M|void us_internal_timer_sweep(struct us_loop_t *loop) {
   86|  2.08M|    struct us_internal_loop_data_t *loop_data = &loop->data;
   87|       |    /* For all socket contexts in this loop */
   88|  4.17M|    for (loop_data->iterator = loop_data->head; loop_data->iterator; loop_data->iterator = loop_data->iterator->next) {
  ------------------
  |  Branch (88:49): [True: 2.08M, False: 2.08M]
  ------------------
   89|       |
   90|  2.08M|        struct us_socket_context_t *context = loop_data->iterator;
   91|       |
   92|       |        /* Update this context's timestamps (this could be moved to loop and done once) */
   93|  2.08M|        context->global_tick++;
   94|  2.08M|        unsigned char short_ticks = context->timestamp = context->global_tick % 240;
   95|  2.08M|        unsigned char long_ticks = context->long_timestamp = (context->global_tick / 15) % 240;
   96|       |
   97|       |        /* Begin at head */
   98|  2.08M|        struct us_socket_t *s = context->head_sockets;
   99|  2.09M|        while (s) {
  ------------------
  |  Branch (99:16): [True: 47.6k, False: 2.04M]
  ------------------
  100|       |            /* Seek until end or timeout found (tightest loop) */
  101|  82.8k|            while (1) {
  ------------------
  |  Branch (101:20): [Folded - Ignored]
  ------------------
  102|       |                /* We only read from 1 random cache line here */
  103|  82.8k|                if (short_ticks == s->timeout || long_ticks == s->long_timeout) {
  ------------------
  |  Branch (103:21): [True: 1.79k, False: 81.0k]
  |  Branch (103:50): [True: 0, False: 81.0k]
  ------------------
  104|  1.79k|                    break;
  105|  1.79k|                }
  106|       |
  107|       |                /* Did we reach the end without a find? */
  108|  81.0k|                if ((s = s->next) == 0) {
  ------------------
  |  Branch (108:21): [True: 45.8k, False: 35.2k]
  ------------------
  109|  45.8k|                    goto next_context;
  110|  45.8k|                }
  111|  81.0k|            }
  112|       |
  113|       |            /* Here we have a timeout to emit (slow path) */
  114|  1.79k|            context->iterator = s;
  115|       |
  116|  1.79k|            if (short_ticks == s->timeout) {
  ------------------
  |  Branch (116:17): [True: 1.79k, False: 0]
  ------------------
  117|  1.79k|                s->timeout = 255;
  118|  1.79k|                context->on_socket_timeout(s);
  119|  1.79k|            }
  120|       |
  121|  1.79k|            if (context->iterator == s && long_ticks == s->long_timeout) {
  ------------------
  |  Branch (121:17): [True: 0, False: 1.79k]
  |  Branch (121:43): [True: 0, False: 0]
  ------------------
  122|      0|                s->long_timeout = 255;
  123|      0|                context->on_socket_long_timeout(s);
  124|      0|            }   
  125|       |
  126|       |            /* Check for unlink / link (if the event handler did not modify the chain, we step 1) */
  127|  1.79k|            if (s == context->iterator) {
  ------------------
  |  Branch (127:17): [True: 0, False: 1.79k]
  ------------------
  128|      0|                s = s->next;
  129|  1.79k|            } else {
  130|       |                /* The iterator was changed by event handler */
  131|  1.79k|                s = context->iterator;
  132|  1.79k|            }
  133|  1.79k|        }
  134|       |        /* We always store a 0 to context->iterator here since we are no longer iterating this context */
  135|  2.08M|        next_context:
  136|  2.08M|        context->iterator = 0;
  137|  2.08M|    }
  138|  2.08M|}
us_internal_handle_low_priority_sockets:
  145|  2.55M|void us_internal_handle_low_priority_sockets(struct us_loop_t *loop) {
  146|  2.55M|    struct us_internal_loop_data_t *loop_data = &loop->data;
  147|  2.55M|    struct us_socket_t *s;
  148|       |
  149|  2.55M|    loop_data->low_prio_budget = MAX_LOW_PRIO_SOCKETS_PER_LOOP_ITERATION;
  150|       |
  151|  2.55M|    for (s = loop_data->low_prio_head; s && loop_data->low_prio_budget > 0; s = loop_data->low_prio_head, loop_data->low_prio_budget--) {
  ------------------
  |  Branch (151:40): [True: 0, False: 2.55M]
  |  Branch (151:45): [True: 0, False: 0]
  ------------------
  152|       |        /* Unlink this socket from the low-priority queue */
  153|      0|        loop_data->low_prio_head = s->next;
  154|      0|        if (s->next) s->next->prev = 0;
  ------------------
  |  Branch (154:13): [True: 0, False: 0]
  ------------------
  155|      0|        s->next = 0;
  156|       |
  157|      0|        us_internal_socket_context_link_socket(s->context, s);
  158|      0|        us_poll_change(&s->p, us_socket_context(0, s)->loop, us_poll_events(&s->p) | LIBUS_SOCKET_READABLE);
  ------------------
  |  |   27|      0|#define LIBUS_SOCKET_READABLE EPOLLIN
  ------------------
  159|       |
  160|      0|        s->low_prio_state = 2;
  161|      0|    }
  162|  2.55M|}
us_internal_free_closed_sockets:
  165|  2.55M|void us_internal_free_closed_sockets(struct us_loop_t *loop) {
  166|       |    /* Free all closed sockets (maybe it is better to reverse order?) */
  167|  2.55M|    if (loop->data.closed_head) {
  ------------------
  |  Branch (167:9): [True: 174k, False: 2.37M]
  ------------------
  168|  1.18M|        for (struct us_socket_t *s = loop->data.closed_head; s; ) {
  ------------------
  |  Branch (168:62): [True: 1.01M, False: 174k]
  ------------------
  169|  1.01M|            struct us_socket_t *next = s->next;
  170|  1.01M|            us_poll_free((struct us_poll_t *) s, loop);
  171|  1.01M|            s = next;
  172|  1.01M|        }
  173|   174k|        loop->data.closed_head = 0;
  174|   174k|    }
  175|  2.55M|}
sweep_timer_cb:
  177|  2.08M|void sweep_timer_cb(struct us_internal_callback_t *cb) {
  178|  2.08M|    us_internal_timer_sweep(cb->loop);
  179|  2.08M|}
us_internal_loop_pre:
  186|  2.55M|void us_internal_loop_pre(struct us_loop_t *loop) {
  187|  2.55M|    loop->data.iteration_nr++;
  188|  2.55M|    us_internal_handle_low_priority_sockets(loop);
  189|  2.55M|    loop->data.pre_cb(loop);
  190|  2.55M|}
us_internal_loop_post:
  192|  2.55M|void us_internal_loop_post(struct us_loop_t *loop) {
  193|  2.55M|    us_internal_free_closed_sockets(loop);
  194|  2.55M|    loop->data.post_cb(loop);
  195|  2.55M|}
us_internal_dispatch_ready_poll:
  197|  9.24M|void us_internal_dispatch_ready_poll(struct us_poll_t *p, int error, int events) {
  198|  9.24M|    switch (us_internal_poll_type(p)) {
  ------------------
  |  Branch (198:13): [True: 0, False: 9.24M]
  ------------------
  199|  6.17M|    case POLL_TYPE_CALLBACK: {
  ------------------
  |  Branch (199:5): [True: 6.17M, False: 3.07M]
  ------------------
  200|  6.17M|            struct us_internal_callback_t *cb = (struct us_internal_callback_t *) p;
  201|       |            /* Timers, asyncs should accept (read), while UDP sockets should obviously not */
  202|  6.17M|            if (!cb->leave_poll_ready) {
  ------------------
  |  Branch (202:17): [True: 6.17M, False: 0]
  ------------------
  203|       |                /* Let's just have this macro to silence the CodeQL alert regarding empty function when using libuv */
  204|  6.17M|    #ifndef LIBUS_USE_LIBUV
  205|  6.17M|                us_internal_accept_poll_event(p);
  206|  6.17M|    #endif
  207|  6.17M|            }
  208|  6.17M|            cb->cb(cb->cb_expects_the_loop ? (struct us_internal_callback_t *) cb->loop : (struct us_internal_callback_t *) &cb->p);
  ------------------
  |  Branch (208:20): [True: 2.04M, False: 4.13M]
  ------------------
  209|  6.17M|        }
  210|  6.17M|        break;
  211|  2.01M|    case POLL_TYPE_SEMI_SOCKET: {
  ------------------
  |  Branch (211:5): [True: 2.01M, False: 7.22M]
  ------------------
  212|       |            /* Both connect and listen sockets are semi-sockets
  213|       |             * but they poll for different events */
  214|  2.01M|            if (us_poll_events(p) == LIBUS_SOCKET_WRITABLE) {
  ------------------
  |  |   28|  2.01M|#define LIBUS_SOCKET_WRITABLE EPOLLOUT
  ------------------
  |  Branch (214:17): [True: 0, False: 2.01M]
  ------------------
  215|      0|                struct us_socket_t *s = (struct us_socket_t *) p;
  216|       |
  217|       |                /* It is perfectly possible to come here with an error */
  218|      0|                if (error) {
  ------------------
  |  Branch (218:21): [True: 0, False: 0]
  ------------------
  219|       |                    /* Emit error, close without emitting on_close */
  220|      0|                    s->context->on_connect_error(s, 0);
  221|      0|                    us_socket_close_connecting(0, s);
  222|      0|                } else {
  223|       |                    /* All sockets poll for readable */
  224|      0|                    us_poll_change(p, s->context->loop, LIBUS_SOCKET_READABLE);
  ------------------
  |  |   27|      0|#define LIBUS_SOCKET_READABLE EPOLLIN
  ------------------
  225|       |
  226|       |                    /* We always use nodelay */
  227|      0|                    bsd_socket_nodelay(us_poll_fd(p), 1);
  228|       |
  229|       |                    /* We are now a proper socket */
  230|      0|                    us_internal_poll_set_type(p, POLL_TYPE_SOCKET);
  231|       |
  232|       |                    /* If we used a connection timeout we have to reset it here */
  233|      0|                    us_socket_timeout(0, s, 0);
  234|       |
  235|      0|                    s->context->on_open(s, 1, 0, 0);
  236|      0|                }
  237|  2.01M|            } else {
  238|  2.01M|                struct us_listen_socket_t *listen_socket = (struct us_listen_socket_t *) p;
  239|  2.01M|                struct bsd_addr_t addr;
  240|       |
  241|  2.01M|                LIBUS_SOCKET_DESCRIPTOR client_fd = bsd_accept_socket(us_poll_fd(p), &addr);
  ------------------
  |  |   38|  2.01M|#define LIBUS_SOCKET_DESCRIPTOR int
  ------------------
  242|  2.01M|                if (client_fd == LIBUS_SOCKET_ERROR) {
  ------------------
  |  |   44|  2.01M|#define LIBUS_SOCKET_ERROR -1
  ------------------
  |  Branch (242:21): [True: 1.88M, False: 136k]
  ------------------
  243|       |                    /* Todo: start timer here */
  244|       |
  245|  1.88M|                } else {
  246|       |
  247|       |                    /* Todo: stop timer if any */
  248|       |
  249|  1.01M|                    do {
  250|  1.01M|                        struct us_poll_t *accepted_p = us_create_poll(us_socket_context(0, &listen_socket->s)->loop, 0, sizeof(struct us_socket_t) - sizeof(struct us_poll_t) + listen_socket->socket_ext_size);
  251|  1.01M|                        us_poll_init(accepted_p, client_fd, POLL_TYPE_SOCKET);
  252|  1.01M|                        us_poll_start(accepted_p, listen_socket->s.context->loop, LIBUS_SOCKET_READABLE);
  ------------------
  |  |   27|  1.01M|#define LIBUS_SOCKET_READABLE EPOLLIN
  ------------------
  253|       |
  254|  1.01M|                        struct us_socket_t *s = (struct us_socket_t *) accepted_p;
  255|       |
  256|  1.01M|                        s->context = listen_socket->s.context;
  257|  1.01M|                        s->timeout = 255;
  258|  1.01M|                        s->long_timeout = 255;
  259|  1.01M|                        s->low_prio_state = 0;
  260|       |
  261|       |                        /* We always use nodelay */
  262|  1.01M|                        bsd_socket_nodelay(client_fd, 1);
  263|       |
  264|  1.01M|                        us_internal_socket_context_link_socket(listen_socket->s.context, s);
  265|       |
  266|  1.01M|                        listen_socket->s.context->on_open(s, 0, bsd_addr_get_ip(&addr), bsd_addr_get_ip_length(&addr));
  267|       |
  268|       |                        /* Exit accept loop if listen socket was closed in on_open handler */
  269|  1.01M|                        if (us_socket_is_closed(0, &listen_socket->s)) {
  ------------------
  |  Branch (269:29): [True: 0, False: 1.01M]
  ------------------
  270|      0|                            break;
  271|      0|                        }
  272|       |
  273|  1.01M|                    } while ((client_fd = bsd_accept_socket(us_poll_fd(p), &addr)) != LIBUS_SOCKET_ERROR);
  ------------------
  |  |   44|  1.01M|#define LIBUS_SOCKET_ERROR -1
  ------------------
  |  Branch (273:30): [True: 873k, False: 136k]
  ------------------
  274|   136k|                }
  275|  2.01M|            }
  276|  2.01M|        }
  277|      0|        break;
  278|      0|    case POLL_TYPE_SOCKET_SHUT_DOWN:
  ------------------
  |  Branch (278:5): [True: 0, False: 9.24M]
  ------------------
  279|  1.05M|    case POLL_TYPE_SOCKET: {
  ------------------
  |  Branch (279:5): [True: 1.05M, False: 8.19M]
  ------------------
  280|       |            /* We should only use s, no p after this point */
  281|  1.05M|            struct us_socket_t *s = (struct us_socket_t *) p;
  282|       |
  283|       |            /* Such as epollerr epollhup */
  284|  1.05M|            if (error) {
  ------------------
  |  Branch (284:17): [True: 887k, False: 164k]
  ------------------
  285|       |                /* Todo: decide what code we give here */
  286|   887k|                s = us_socket_close(0, s, 0, NULL);
  287|   887k|                return;
  288|   887k|            }
  289|       |
  290|   164k|            if (events & LIBUS_SOCKET_WRITABLE) {
  ------------------
  |  |   28|   164k|#define LIBUS_SOCKET_WRITABLE EPOLLOUT
  ------------------
  |  Branch (290:17): [True: 10.5k, False: 153k]
  ------------------
  291|       |                /* Note: if we failed a write as a socket of one loop then adopted
  292|       |                 * to another loop, this will be wrong. Absurd case though */
  293|  10.5k|                s->context->loop->data.last_write_failed = 0;
  294|       |
  295|  10.5k|                s = s->context->on_writable(s);
  296|       |
  297|  10.5k|                if (us_socket_is_closed(0, s)) {
  ------------------
  |  Branch (297:21): [True: 1.54k, False: 8.95k]
  ------------------
  298|  1.54k|                    return;
  299|  1.54k|                }
  300|       |
  301|       |                /* If we have no failed write or if we shut down, then stop polling for more writable */
  302|  8.95k|                if (!s->context->loop->data.last_write_failed || us_socket_is_shut_down(0, s)) {
  ------------------
  |  Branch (302:21): [True: 973, False: 7.98k]
  |  Branch (302:66): [True: 0, False: 7.98k]
  ------------------
  303|    973|                    us_poll_change(&s->p, us_socket_context(0, s)->loop, us_poll_events(&s->p) & LIBUS_SOCKET_READABLE);
  ------------------
  |  |   27|    973|#define LIBUS_SOCKET_READABLE EPOLLIN
  ------------------
  304|    973|                }
  305|  8.95k|            }
  306|       |
  307|   162k|            if (events & LIBUS_SOCKET_READABLE) {
  ------------------
  |  |   27|   162k|#define LIBUS_SOCKET_READABLE EPOLLIN
  ------------------
  |  Branch (307:17): [True: 160k, False: 2.25k]
  ------------------
  308|       |                /* Contexts may prioritize down sockets that are currently readable, e.g. when SSL handshake has to be done.
  309|       |                 * SSL handshakes are CPU intensive, so we limit the number of handshakes per loop iteration, and move the rest
  310|       |                 * to the low-priority queue */
  311|   160k|                if (s->context->is_low_prio(s)) {
  ------------------
  |  Branch (311:21): [True: 0, False: 160k]
  ------------------
  312|      0|                    if (s->low_prio_state == 2) {
  ------------------
  |  Branch (312:25): [True: 0, False: 0]
  ------------------
  313|      0|                        s->low_prio_state = 0; /* Socket has been delayed and now it's time to process incoming data for one iteration */
  314|      0|                    } else if (s->context->loop->data.low_prio_budget > 0) {
  ------------------
  |  Branch (314:32): [True: 0, False: 0]
  ------------------
  315|      0|                        s->context->loop->data.low_prio_budget--; /* Still having budget for this iteration - do normal processing */
  316|      0|                    } else {
  317|      0|                        us_poll_change(&s->p, us_socket_context(0, s)->loop, us_poll_events(&s->p) & LIBUS_SOCKET_WRITABLE);
  ------------------
  |  |   28|      0|#define LIBUS_SOCKET_WRITABLE EPOLLOUT
  ------------------
  318|      0|                        us_internal_socket_context_unlink_socket(s->context, s);
  319|       |
  320|       |                        /* Link this socket to the low-priority queue - we use a LIFO queue, to prioritize newer clients that are
  321|       |                         * maybe not already timeouted - sounds unfair, but works better in real-life with smaller client-timeouts
  322|       |                         * under high load */
  323|      0|                        s->prev = 0;
  324|      0|                        s->next = s->context->loop->data.low_prio_head;
  325|      0|                        if (s->next) s->next->prev = s;
  ------------------
  |  Branch (325:29): [True: 0, False: 0]
  ------------------
  326|      0|                        s->context->loop->data.low_prio_head = s;
  327|       |
  328|      0|                        s->low_prio_state = 1;
  329|       |
  330|      0|                        break;
  331|      0|                    }
  332|      0|                }
  333|       |
  334|   160k|                int length = bsd_recv(us_poll_fd(&s->p), s->context->loop->data.recv_buf + LIBUS_RECV_BUFFER_PADDING, LIBUS_RECV_BUFFER_LENGTH, 0);
  ------------------
  |  |   26|   160k|#define LIBUS_RECV_BUFFER_PADDING 32
  ------------------
                              int length = bsd_recv(us_poll_fd(&s->p), s->context->loop->data.recv_buf + LIBUS_RECV_BUFFER_PADDING, LIBUS_RECV_BUFFER_LENGTH, 0);
  ------------------
  |  |   22|   160k|#define LIBUS_RECV_BUFFER_LENGTH 524288
  ------------------
  335|   160k|                if (length > 0) {
  ------------------
  |  Branch (335:21): [True: 132k, False: 27.2k]
  ------------------
  336|   132k|                    s = s->context->on_data(s, s->context->loop->data.recv_buf + LIBUS_RECV_BUFFER_PADDING, length);
  ------------------
  |  |   26|   132k|#define LIBUS_RECV_BUFFER_PADDING 32
  ------------------
  337|   132k|                } else if (!length) {
  ------------------
  |  Branch (337:28): [True: 26.0k, False: 1.21k]
  ------------------
  338|  26.0k|                    if (us_socket_is_shut_down(0, s)) {
  ------------------
  |  Branch (338:25): [True: 0, False: 26.0k]
  ------------------
  339|       |                        /* We got FIN back after sending it */
  340|       |                        /* Todo: We should give "CLEAN SHUTDOWN" as reason here */
  341|      0|                        s = us_socket_close(0, s, 0, NULL);
  342|  26.0k|                    } else {
  343|       |                        /* We got FIN, so stop polling for readable */
  344|  26.0k|                        us_poll_change(&s->p, us_socket_context(0, s)->loop, us_poll_events(&s->p) & LIBUS_SOCKET_WRITABLE);
  ------------------
  |  |   28|  26.0k|#define LIBUS_SOCKET_WRITABLE EPOLLOUT
  ------------------
  345|  26.0k|                        s = s->context->on_end(s);
  346|  26.0k|                    }
  347|  26.0k|                } else if (length == LIBUS_SOCKET_ERROR && !bsd_would_block()) {
  ------------------
  |  |   44|  2.42k|#define LIBUS_SOCKET_ERROR -1
  ------------------
  |  Branch (347:28): [True: 1.21k, False: 0]
  |  Branch (347:60): [True: 0, False: 1.21k]
  ------------------
  348|       |                    /* Todo: decide also here what kind of reason we should give */
  349|      0|                    s = us_socket_close(0, s, 0, NULL);
  350|      0|                }
  351|   160k|            }
  352|   162k|        }
  353|   162k|        break;
  354|  9.24M|    }
  355|  9.24M|}
us_loop_integrate:
  358|  1.65k|void us_loop_integrate(struct us_loop_t *loop) {
  359|  1.65k|    us_timer_set(loop->data.sweep_timer, (void (*)(struct us_timer_t *)) sweep_timer_cb, LIBUS_TIMEOUT_GRANULARITY * 1000, LIBUS_TIMEOUT_GRANULARITY * 1000);
  ------------------
  |  |   24|  1.65k|#define LIBUS_TIMEOUT_GRANULARITY 4
  ------------------
                  us_timer_set(loop->data.sweep_timer, (void (*)(struct us_timer_t *)) sweep_timer_cb, LIBUS_TIMEOUT_GRANULARITY * 1000, LIBUS_TIMEOUT_GRANULARITY * 1000);
  ------------------
  |  |   24|  1.65k|#define LIBUS_TIMEOUT_GRANULARITY 4
  ------------------
  360|  1.65k|}
us_loop_ext:
  362|  7.94M|void *us_loop_ext(struct us_loop_t *loop) {
  363|  7.94M|    return loop + 1;
  364|  7.94M|}

us_socket_context:
   52|  3.96M|struct us_socket_context_t *us_socket_context(int ssl, struct us_socket_t *s) {
   53|  3.96M|    return s->context;
   54|  3.96M|}
us_socket_timeout:
   56|  1.08M|void us_socket_timeout(int ssl, struct us_socket_t *s, unsigned int seconds) {
   57|  1.08M|    if (seconds) {
  ------------------
  |  Branch (57:9): [True: 1.05M, False: 27.4k]
  ------------------
   58|  1.05M|        s->timeout = ((unsigned int)s->context->timestamp + ((seconds + 3) >> 2)) % 240;
   59|  1.05M|    } else {
   60|  27.4k|        s->timeout = 255;
   61|  27.4k|    }
   62|  1.08M|}
us_socket_is_closed:
   78|  2.64M|int us_socket_is_closed(int ssl, struct us_socket_t *s) {
   79|  2.64M|    return s->prev == (struct us_socket_t *) s->context;
   80|  2.64M|}
us_socket_close:
  107|  1.01M|struct us_socket_t *us_socket_close(int ssl, struct us_socket_t *s, int code, void *reason) {
  108|  1.01M|    if (!us_socket_is_closed(0, s)) {
  ------------------
  |  Branch (108:9): [True: 1.01M, False: 0]
  ------------------
  109|  1.01M|        if (s->low_prio_state == 1) {
  ------------------
  |  Branch (109:13): [True: 0, False: 1.01M]
  ------------------
  110|       |            /* Unlink this socket from the low-priority queue */
  111|      0|            if (!s->prev) s->context->loop->data.low_prio_head = s->next;
  ------------------
  |  Branch (111:17): [True: 0, False: 0]
  ------------------
  112|      0|            else s->prev->next = s->next;
  113|       |
  114|      0|            if (s->next) s->next->prev = s->prev;
  ------------------
  |  Branch (114:17): [True: 0, False: 0]
  ------------------
  115|       |
  116|      0|            s->prev = 0;
  117|      0|            s->next = 0;
  118|      0|            s->low_prio_state = 0;
  119|  1.01M|        } else {
  120|  1.01M|            us_internal_socket_context_unlink_socket(s->context, s);
  121|  1.01M|        }
  122|  1.01M|        us_poll_stop((struct us_poll_t *) s, s->context->loop);
  123|  1.01M|        bsd_close_socket(us_poll_fd((struct us_poll_t *) s));
  124|       |
  125|       |        /* Link this socket to the close-list and let it be deleted after this iteration */
  126|  1.01M|        s->next = s->context->loop->data.closed_head;
  127|  1.01M|        s->context->loop->data.closed_head = s;
  128|       |
  129|       |        /* Any socket with prev = context is marked as closed */
  130|  1.01M|        s->prev = (struct us_socket_t *) s->context;
  131|       |
  132|  1.01M|        return s->context->on_close(s, code, reason);
  133|  1.01M|    }
  134|      0|    return s;
  135|  1.01M|}
us_socket_write:
  164|   141k|int us_socket_write(int ssl, struct us_socket_t *s, const char *data, int length, int msg_more) {
  165|       |#ifndef LIBUS_NO_SSL
  166|       |    if (ssl) {
  167|       |        return us_internal_ssl_socket_write((struct us_internal_ssl_socket_t *) s, data, length, msg_more);
  168|       |    }
  169|       |#endif
  170|       |
  171|   141k|    if (us_socket_is_closed(ssl, s) || us_socket_is_shut_down(ssl, s)) {
  ------------------
  |  Branch (171:9): [True: 0, False: 141k]
  |  Branch (171:40): [True: 0, False: 141k]
  ------------------
  172|      0|        return 0;
  173|      0|    }
  174|       |
  175|   141k|    int written = bsd_send(us_poll_fd(&s->p), data, length, msg_more);
  176|   141k|    if (written != length) {
  ------------------
  |  Branch (176:9): [True: 132k, False: 9.42k]
  ------------------
  177|   132k|        s->context->loop->data.last_write_failed = 1;
  178|   132k|        us_poll_change(&s->p, s->context->loop, LIBUS_SOCKET_READABLE | LIBUS_SOCKET_WRITABLE);
  ------------------
  |  |   27|   132k|#define LIBUS_SOCKET_READABLE EPOLLIN
  ------------------
                      us_poll_change(&s->p, s->context->loop, LIBUS_SOCKET_READABLE | LIBUS_SOCKET_WRITABLE);
  ------------------
  |  |   28|   132k|#define LIBUS_SOCKET_WRITABLE EPOLLOUT
  ------------------
  179|   132k|    }
  180|       |
  181|   141k|    return written < 0 ? 0 : written;
  ------------------
  |  Branch (181:12): [True: 946, False: 140k]
  ------------------
  182|   141k|}
us_socket_ext:
  184|  2.59M|void *us_socket_ext(int ssl, struct us_socket_t *s) {
  185|       |#ifndef LIBUS_NO_SSL
  186|       |    if (ssl) {
  187|       |        return us_internal_ssl_socket_ext((struct us_internal_ssl_socket_t *) s);
  188|       |    }
  189|       |#endif
  190|       |
  191|  2.59M|    return s + 1;
  192|  2.59M|}
us_socket_is_shut_down:
  194|   422k|int us_socket_is_shut_down(int ssl, struct us_socket_t *s) {
  195|       |#ifndef LIBUS_NO_SSL
  196|       |    if (ssl) {
  197|       |        return us_internal_ssl_socket_is_shut_down((struct us_internal_ssl_socket_t *) s);
  198|       |    }
  199|       |#endif
  200|       |
  201|   422k|    return us_internal_poll_type(&s->p) == POLL_TYPE_SOCKET_SHUT_DOWN;
  202|   422k|}
us_socket_shutdown:
  204|  90.8k|void us_socket_shutdown(int ssl, struct us_socket_t *s) {
  205|       |#ifndef LIBUS_NO_SSL
  206|       |    if (ssl) {
  207|       |        us_internal_ssl_socket_shutdown((struct us_internal_ssl_socket_t *) s);
  208|       |        return;
  209|       |    }
  210|       |#endif
  211|       |
  212|       |    /* Todo: should we emit on_close if calling shutdown on an already half-closed socket?
  213|       |     * We need more states in that case, we need to track RECEIVED_FIN
  214|       |     * so far, the app has to track this and call close as needed */
  215|  90.8k|    if (!us_socket_is_closed(ssl, s) && !us_socket_is_shut_down(ssl, s)) {
  ------------------
  |  Branch (215:9): [True: 90.8k, False: 0]
  |  Branch (215:41): [True: 90.8k, False: 0]
  ------------------
  216|  90.8k|        us_internal_poll_set_type(&s->p, POLL_TYPE_SOCKET_SHUT_DOWN);
  217|  90.8k|        us_poll_change(&s->p, s->context->loop, us_poll_events(&s->p) & LIBUS_SOCKET_READABLE);
  ------------------
  |  |   27|  90.8k|#define LIBUS_SOCKET_READABLE EPOLLIN
  ------------------
  218|  90.8k|        bsd_shutdown_socket(us_poll_fd((struct us_poll_t *) s));
  219|  90.8k|    }
  220|  90.8k|}

_Z4testv:
   10|  1.65k|void test() {
   11|       |
   12|  1.65k|    {
   13|       |        /* Keep in mind that uWS::SSLApp({options}) is the same as uWS::App() when compiled without SSL support.
   14|       |        * You may swap to using uWS:App() if you don't need SSL */
   15|  1.65k|        auto app = uWS::App({
   16|       |            /* There are example certificates in uWebSockets.js repo */
   17|  1.65k|            .key_file_name = "../misc/key.pem",
   18|  1.65k|            .cert_file_name = "../misc/cert.pem",
   19|  1.65k|            .passphrase = "1234"
   20|  1.65k|        }).get("/*", [](auto *res, auto *req) {
   21|  1.65k|            auto aborted = std::make_shared<bool>();
   22|  1.65k|            *aborted = false;
   23|  1.65k|            res->onAborted([aborted]() {
   24|  1.65k|                *aborted = true;
   25|  1.65k|            });
   26|       |
   27|  1.65k|            uWS::Loop::get()->defer([res, aborted]() {
   28|  1.65k|                if (!*aborted) {
   29|  1.65k|                    res->cork([res, aborted]() {
   30|       |                        // Todo: also test upgrade to websocket here
   31|  1.65k|                        res->end("Hello async!");
   32|  1.65k|                    });
   33|  1.65k|                }
   34|  1.65k|            });
   35|  1.65k|        }).listen(9001, [](auto *listenSocket) {
   36|  1.65k|            listen_socket = listenSocket;
   37|  1.65k|        });
   38|       |
   39|  1.65k|        app.run();
   40|  1.65k|    }
   41|  1.65k|    uWS::Loop::get()->free();
   42|  1.65k|}
_Z8teardownv:
   45|  1.64k|void teardown() {
   46|       |	/* If we are called twice there's a bug (it potentially could if
   47|       |	 * all open sockets cannot be error-closed in one epoll_wait call).
   48|       |	 * But we only allow 1k FDs and we have a buffer of 1024 from epoll_wait */
   49|  1.64k|	if (!listen_socket) {
  ------------------
  |  Branch (49:6): [True: 0, False: 1.64k]
  ------------------
   50|      0|		exit(-1);
   51|      0|	}
   52|       |
   53|       |	/* We might have open sockets still, and these will be error-closed by epoll_wait */
   54|       |	// us_socket_context_close - close all open sockets created with this socket context
   55|  1.64k|    if (listen_socket) {
  ------------------
  |  Branch (55:9): [True: 1.64k, False: 0]
  ------------------
   56|  1.64k|        us_listen_socket_close(0, listen_socket);
   57|  1.64k|        listen_socket = NULL;
   58|  1.64k|    }
   59|  1.64k|}
AsyncEpollHelloWorld.cpp:_ZZ4testvENK3$_0clIN3uWS12HttpResponseILb0EEENS1_11HttpRequestEEEDaPT_PT0_:
   20|  23.2k|        }).get("/*", [](auto *res, auto *req) {
   21|  23.2k|            auto aborted = std::make_shared<bool>();
   22|  23.2k|            *aborted = false;
   23|  23.2k|            res->onAborted([aborted]() {
   24|  23.2k|                *aborted = true;
   25|  23.2k|            });
   26|       |
   27|  23.2k|            uWS::Loop::get()->defer([res, aborted]() {
   28|  23.2k|                if (!*aborted) {
   29|  23.2k|                    res->cork([res, aborted]() {
   30|       |                        // Todo: also test upgrade to websocket here
   31|  23.2k|                        res->end("Hello async!");
   32|  23.2k|                    });
   33|  23.2k|                }
   34|  23.2k|            });
   35|  23.2k|        }).listen(9001, [](auto *listenSocket) {
AsyncEpollHelloWorld.cpp:_ZZZ4testvENK3$_0clIN3uWS12HttpResponseILb0EEENS1_11HttpRequestEEEDaPT_PT0_ENKUlvE_clEv:
   23|  10.1k|            res->onAborted([aborted]() {
   24|  10.1k|                *aborted = true;
   25|  10.1k|            });
AsyncEpollHelloWorld.cpp:_ZZZ4testvENK3$_0clIN3uWS12HttpResponseILb0EEENS1_11HttpRequestEEEDaPT_PT0_ENKUlvE0_clEv:
   27|  22.6k|            uWS::Loop::get()->defer([res, aborted]() {
   28|  22.6k|                if (!*aborted) {
  ------------------
  |  Branch (28:21): [True: 13.0k, False: 9.54k]
  ------------------
   29|  13.0k|                    res->cork([res, aborted]() {
   30|       |                        // Todo: also test upgrade to websocket here
   31|  13.0k|                        res->end("Hello async!");
   32|  13.0k|                    });
   33|  13.0k|                }
   34|  22.6k|            });
AsyncEpollHelloWorld.cpp:_ZZZZ4testvENK3$_0clIN3uWS12HttpResponseILb0EEENS1_11HttpRequestEEEDaPT_PT0_ENKUlvE0_clEvENKUlvE_clEv:
   29|  13.0k|                    res->cork([res, aborted]() {
   30|       |                        // Todo: also test upgrade to websocket here
   31|  13.0k|                        res->end("Hello async!");
   32|  13.0k|                    });
AsyncEpollHelloWorld.cpp:_ZZ4testvENK3$_1clI18us_listen_socket_tEEDaPT_:
   35|  1.65k|        }).listen(9001, [](auto *listenSocket) {
   36|  1.65k|            listen_socket = listenSocket;
   37|  1.65k|        });

set_consumable_data:
   71|  1.65k|void set_consumable_data(const unsigned char *new_data, int new_length) {
   72|  1.65k|	consumable_data = (unsigned char *) new_data;
   73|  1.65k|	consumable_data_length = new_length;
   74|  1.65k|}
consume_byte:
   77|  3.03M|int consume_byte(unsigned char *b) {
   78|  3.03M|	if (consumable_data_length) {
  ------------------
  |  Branch (78:6): [True: 3.03M, False: 963]
  ------------------
   79|  3.03M|		*b = consumable_data[0];
   80|  3.03M|		consumable_data++;
   81|  3.03M|		consumable_data_length--;
   82|  3.03M|		return 0;
   83|  3.03M|	}
   84|    963|	return -1;
   85|  3.03M|}
allocate_fd:
   90|  1.01M|int allocate_fd() {
   91|       |	// this can be massively optimized by having a list of free blocks or the like
   92|   264M|	for (int fd = 0; fd < MAX_FDS; fd++) {
  ------------------
  |  Branch (92:19): [True: 264M, False: 422]
  ------------------
   93|   264M|		if (!fd_to_file[fd]) {
  ------------------
  |  Branch (93:7): [True: 1.01M, False: 263M]
  ------------------
   94|  1.01M|			num_fds++;
   95|  1.01M|			return fd + RESERVED_SYSTEM_FDS;
   96|  1.01M|		}
   97|   264M|	}
   98|    422|	return -1;
   99|  1.01M|}
init_fd:
  102|  1.01M|void init_fd(int fd, int type, struct file *f) {
  103|  1.01M|	if (fd >= RESERVED_SYSTEM_FDS) {
  ------------------
  |  Branch (103:6): [True: 1.01M, False: 0]
  ------------------
  104|  1.01M|		fd_to_file[fd - RESERVED_SYSTEM_FDS] = f;
  105|  1.01M|		fd_to_file[fd - RESERVED_SYSTEM_FDS]->type = type;
  106|  1.01M|		fd_to_file[fd - RESERVED_SYSTEM_FDS]->next = NULL;
  107|  1.01M|		fd_to_file[fd - RESERVED_SYSTEM_FDS]->prev = NULL;
  108|  1.01M|	}
  109|  1.01M|}
map_fd:
  111|  14.3M|struct file *map_fd(int fd) {
  112|  14.3M|	if (fd >= RESERVED_SYSTEM_FDS && fd < MAX_FDS + RESERVED_SYSTEM_FDS) {
  ------------------
  |  Branch (112:6): [True: 14.3M, False: 0]
  |  Branch (112:35): [True: 14.3M, False: 0]
  ------------------
  113|  14.3M|		return fd_to_file[fd - RESERVED_SYSTEM_FDS];
  114|  14.3M|	}
  115|      0|	return NULL;
  116|  14.3M|}
free_fd:
  119|  1.01M|int free_fd(int fd) {
  120|  1.01M|	if (fd >= RESERVED_SYSTEM_FDS && fd < MAX_FDS + RESERVED_SYSTEM_FDS) {
  ------------------
  |  Branch (120:6): [True: 1.01M, False: 0]
  |  Branch (120:35): [True: 1.01M, False: 0]
  ------------------
  121|  1.01M|		if (fd_to_file[fd - RESERVED_SYSTEM_FDS]) {
  ------------------
  |  Branch (121:7): [True: 1.01M, False: 0]
  ------------------
  122|  1.01M|			fd_to_file[fd - RESERVED_SYSTEM_FDS] = 0;
  123|  1.01M|			num_fds--;
  124|  1.01M|			return 0;
  125|  1.01M|		}
  126|  1.01M|	}
  127|       |
  128|      0|	return -1;
  129|  1.01M|}
__wrap_epoll_create1:
  141|  1.65k|int __wrap_epoll_create1(int flags) {
  142|       |
  143|       |	/* Todo: check that we do not allocate more than one epoll FD */
  144|  1.65k|	int fd = allocate_fd();
  145|       |
  146|  1.65k|	if (fd != -1) {
  ------------------
  |  Branch (146:6): [True: 1.65k, False: 0]
  ------------------
  147|  1.65k|		struct epoll_file *ef = (struct epoll_file *)malloc(sizeof(struct epoll_file));
  148|       |
  149|       |		/* Init the epoll_file */
  150|  1.65k|		ef->poll_set_head = NULL;
  151|  1.65k|		ef->poll_set_tail = NULL;
  152|       |
  153|  1.65k|		init_fd(fd, FD_TYPE_EPOLL, (struct file *)ef);
  154|  1.65k|	}
  155|       |
  156|       |#ifdef PRINTF_DEBUG
  157|       |	printf("epoll_create1 returning epfd: %d\n", fd);
  158|       |#endif
  159|       |
  160|  1.65k|	return fd;
  161|  1.65k|}
__wrap_epoll_ctl:
  165|  2.23M|int __wrap_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) {
  166|       |
  167|  2.23M|	struct epoll_file *ef = (struct epoll_file *)map_fd(epfd);
  168|  2.23M|	if (!ef) {
  ------------------
  |  Branch (168:6): [True: 0, False: 2.23M]
  ------------------
  169|      0|		return -1;
  170|      0|	}
  171|       |
  172|  2.23M|	struct file *f = (struct file *)map_fd(fd);
  173|  2.23M|	if (!f) {
  ------------------
  |  Branch (173:6): [True: 0, False: 2.23M]
  ------------------
  174|      0|		return -1;
  175|      0|	}
  176|       |
  177|       |	/* We add new polls in the head */
  178|  2.23M|	if (op == EPOLL_CTL_ADD) {
  ------------------
  |  Branch (178:6): [True: 1.01M, False: 1.22M]
  ------------------
  179|       |		// if there is a head already
  180|  1.01M|		if (ef->poll_set_head) {
  ------------------
  |  Branch (180:7): [True: 1.01M, False: 1.65k]
  ------------------
  181|  1.01M|			ef->poll_set_head->prev = f;
  182|       |
  183|       |			// then it will be our next
  184|  1.01M|			f->next = ef->poll_set_head;
  185|  1.01M|		} else {
  186|       |			// if there was no head then we became the tail also
  187|  1.65k|			ef->poll_set_tail = f;
  188|  1.65k|		}
  189|       |
  190|       |		// we are now the head in any case
  191|  1.01M|		ef->poll_set_head = f;
  192|       |
  193|  1.01M|		f->epev = *event;
  194|       |
  195|  1.22M|	} else if (op == EPOLL_CTL_MOD) {
  ------------------
  |  Branch (195:13): [True: 205k, False: 1.01M]
  ------------------
  196|       |		/* Modifying is simply changing the file itself */
  197|   205k|		f->epev = *event;
  198|  1.01M|	} else if (op == EPOLL_CTL_DEL) {
  ------------------
  |  Branch (198:13): [True: 1.01M, False: 0]
  ------------------
  199|       |
  200|  1.01M|		if (f->prev) {
  ------------------
  |  Branch (200:7): [True: 205k, False: 810k]
  ------------------
  201|   205k|			f->prev->next = f->next;
  202|   810k|		} else {
  203|   810k|			ef->poll_set_head = f->next;
  204|   810k|		}
  205|       |
  206|  1.01M|		if (f->next) {
  ------------------
  |  Branch (206:7): [True: 1.01M, False: 1.65k]
  ------------------
  207|  1.01M|			f->next->prev = f->prev;
  208|  1.01M|		} else {
  209|       |			// tail ska vara vår.prev
  210|  1.65k|			ef->poll_set_tail = f->prev;
  211|  1.65k|		}
  212|       |
  213|       |		// a file that is not in the list should be reset to NULL
  214|  1.01M|		f->prev = NULL;
  215|  1.01M|		f->next = NULL;
  216|  1.01M|	}
  217|       |
  218|       |	/* You have to poll for errors and hangups */
  219|  2.23M|	f->epev.events |= EPOLLERR | EPOLLHUP;
  220|       |
  221|  2.23M|	return 0;
  222|  2.23M|}
__wrap_epoll_wait:
  226|  2.55M|               int maxevents, int timeout) {
  227|       |	//printf("epoll_wait: %d\n", 0);
  228|       |
  229|       |#ifdef PRINTF_DEBUG
  230|       |	printf("Calling epoll_wait\n");
  231|       |#endif
  232|       |
  233|  2.55M|	struct epoll_file *ef = (struct epoll_file *)map_fd(epfd);
  234|  2.55M|	if (!ef) {
  ------------------
  |  Branch (234:6): [True: 0, False: 2.55M]
  ------------------
  235|      0|		return -1;
  236|      0|	}
  237|       |
  238|  2.55M|	if (consumable_data_length) {
  ------------------
  |  Branch (238:6): [True: 2.54M, False: 1.64k]
  ------------------
  239|       |
  240|  2.54M|		int ready_events = 0;
  241|       |
  242|  14.8M|		for (struct file *f = ef->poll_set_head; f; f = f->next) {
  ------------------
  |  Branch (242:44): [True: 12.2M, False: 2.54M]
  ------------------
  243|       |
  244|       |
  245|       |			/* Consume one fuzz byte, AND it with the event */
  246|  12.2M|			if (!consumable_data_length) {
  ------------------
  |  Branch (246:8): [True: 313, False: 12.2M]
  ------------------
  247|       |				// break if we have no data
  248|    313|				break;
  249|    313|			}
  250|       |
  251|       |			// here we have the main condition that drives everything
  252|  12.2M|			int ready_event = consumable_data[0] & f->epev.events;
  253|       |
  254|       |			// consume the byte
  255|  12.2M|			consumable_data_length--;
  256|  12.2M|			consumable_data++;
  257|       |
  258|  12.2M|			if (ready_event) {
  ------------------
  |  Branch (258:8): [True: 9.20M, False: 3.08M]
  ------------------
  259|  9.20M|				if (ready_events < maxevents) {
  ------------------
  |  Branch (259:9): [True: 9.20M, False: 0]
  ------------------
  260|  9.20M|					events[ready_events] = f->epev;
  261|       |
  262|       |					// todo: the event should be masked by the byte, not everything it wants shold be given all the time!
  263|  9.20M|					events[ready_events++].events = ready_event;
  264|  9.20M|				} else {
  265|       |					// we are full, break
  266|      0|					break;
  267|      0|				}
  268|  9.20M|			}
  269|       |
  270|  12.2M|		}
  271|       |
  272|  2.54M|		return ready_events;
  273|       |
  274|  2.54M|	} else {
  275|       |
  276|       |#ifdef PRINTF_DEBUG
  277|       |		printf("Calling teardown\n");
  278|       |#endif
  279|  1.64k|		teardown();
  280|       |
  281|       |		// after shutting down the listen socket we clear the whole list (the bug in epoll_ctl remove)
  282|       |		// so the below loop doesn't work - we never close anything more than the listen socket!
  283|       |
  284|       |		/* You don't really need to emit teardown, you could simply emit error on every poll */
  285|       |
  286|  1.64k|		int ready_events = 0;
  287|       |
  288|       |#ifdef PRINTF_DEBUG
  289|       |		printf("Emitting error on every remaining FD\n");
  290|       |#endif
  291|  47.6k|		for (struct file *f = ef->poll_set_head; f; f = f->next) {
  ------------------
  |  Branch (291:44): [True: 46.0k, False: 1.64k]
  ------------------
  292|       |
  293|  46.0k|			if (f->type == FD_TYPE_SOCKET) {
  ------------------
  |  Branch (293:8): [True: 41.1k, False: 4.92k]
  ------------------
  294|       |
  295|  41.1k|				if (ready_events < maxevents) {
  ------------------
  |  Branch (295:9): [True: 41.1k, False: 0]
  ------------------
  296|  41.1k|					events[ready_events] = f->epev;
  297|       |
  298|       |					// todo: the event should be masked by the byte, not everything it wants shold be given all the time!
  299|  41.1k|					events[ready_events++].events = EPOLLERR | EPOLLHUP;
  300|  41.1k|				} else {
  301|       |					// we are full, break
  302|      0|					break;
  303|      0|				}
  304|       |
  305|  41.1k|			}
  306|  46.0k|		}
  307|       |
  308|       |#ifdef PRINTF_DEBUG
  309|       |		printf("Ready events: %d\n", ready_events);
  310|       |#endif
  311|       |
  312|  1.64k|		return ready_events;
  313|  1.64k|	}
  314|  2.55M|}
__wrap_read:
  332|  6.33M|int __wrap_read(int fd, void *buf, size_t count) {
  333|       |
  334|  6.33M|	if (fd < RESERVED_SYSTEM_FDS) {
  ------------------
  |  Branch (334:6): [True: 0, False: 6.33M]
  ------------------
  335|      0|		return __real_read(fd, buf, count);
  336|      0|	}
  337|       |
  338|       |#ifdef PRINTF_DEBUG
  339|       |	printf("Wrapped read\n");
  340|       |#endif
  341|       |
  342|       |	/* Let's try and clear the buffer first */
  343|       |	//memset(buf, 0, count);
  344|       |
  345|  6.33M|	struct file *f = map_fd(fd);
  346|  6.33M|	if (!f) {
  ------------------
  |  Branch (346:6): [True: 0, False: 6.33M]
  ------------------
  347|      0|		return -1;
  348|      0|	}
  349|       |
  350|  6.33M|	errno = 0;
  351|       |
  352|  6.33M|	if (f->type == FD_TYPE_SOCKET) {
  ------------------
  |  Branch (352:6): [True: 160k, False: 6.17M]
  ------------------
  353|       |
  354|   160k|		if (!consumable_data_length) {
  ------------------
  |  Branch (354:7): [True: 1.21k, False: 159k]
  ------------------
  355|  1.21k|			errno = EWOULDBLOCK;
  356|  1.21k|			return -1;
  357|   159k|		} else {
  358|   159k|			int data_available = (unsigned char) consumable_data[0];
  359|   159k|			consumable_data_length--;
  360|   159k|			consumable_data++;
  361|       |
  362|   159k|			if (consumable_data_length < data_available) {
  ------------------
  |  Branch (362:8): [True: 943, False: 158k]
  ------------------
  363|    943|				data_available = consumable_data_length;
  364|    943|			}
  365|       |
  366|   159k|			if (count < data_available) {
  ------------------
  |  Branch (366:8): [True: 0, False: 159k]
  ------------------
  367|      0|				data_available = count;
  368|      0|			}
  369|       |
  370|   159k|			memcpy(buf, consumable_data, data_available);
  371|       |
  372|   159k|			consumable_data_length -= data_available;
  373|   159k|			consumable_data += data_available;
  374|       |
  375|   159k|			return data_available;
  376|   159k|		}
  377|   160k|	}
  378|       |
  379|  6.17M|	if (f->type == FD_TYPE_EVENT) {
  ------------------
  |  Branch (379:6): [True: 2.04M, False: 4.13M]
  ------------------
  380|  2.04M|		memset(buf, 1, 8);
  381|  2.04M|		return 8;
  382|  2.04M|	}
  383|       |
  384|  4.13M|	if (f->type == FD_TYPE_TIMER) {
  ------------------
  |  Branch (384:6): [True: 4.13M, False: 0]
  ------------------
  385|  4.13M|		memset(buf, 1, 8);
  386|  4.13M|		return 8;
  387|  4.13M|	}
  388|       |
  389|      0|	return -1;
  390|  4.13M|}
__wrap_recv:
  393|   160k|int __wrap_recv(int sockfd, void *buf, size_t len, int flags) {
  394|   160k|	return __wrap_read(sockfd, buf, len);
  395|   160k|}
__wrap_send:
  397|   141k|int __wrap_send(int sockfd, const void *buf, size_t len, int flags) {
  398|       |
  399|   141k|	if (consumable_data_length) {
  ------------------
  |  Branch (399:6): [True: 140k, False: 946]
  ------------------
  400|       |		/* We can send len scaled by the 1 byte */
  401|   140k|		unsigned char scale = consumable_data[0];
  402|   140k|		consumable_data++;
  403|   140k|		consumable_data_length--;
  404|       |
  405|   140k|		int written = float(scale) / 255.0f * len;
  406|       |
  407|   140k|		if (written == 0) {
  ------------------
  |  Branch (407:7): [True: 26.5k, False: 114k]
  ------------------
  408|  26.5k|			errno = EWOULDBLOCK;
  409|   114k|		} else {
  410|   114k|			errno = 0;
  411|   114k|		}
  412|       |
  413|   140k|		return written;
  414|   140k|	} else {
  415|    946|		return -1;
  416|    946|	}
  417|   141k|}
__wrap_bind:
  424|  1.65k|int __wrap_bind() {
  425|  1.65k|	return 0;
  426|  1.65k|}
__wrap_setsockopt:
  428|  1.01M|int __wrap_setsockopt() {
  429|  1.01M|	return 0;
  430|  1.01M|}
__wrap_fcntl:
  433|  2.02M|int __wrap_fcntl(int fd, int cmd, ... /* arg */) {
  434|  2.02M|	if (fd < RESERVED_SYSTEM_FDS) {
  ------------------
  |  Branch (434:6): [True: 2, False: 2.02M]
  ------------------
  435|      2|		va_list args;
  436|      2|		va_start(args, cmd);
  437|      2|		int ret = __real_fcntl(fd, cmd, args);
  438|      2|		va_end(args);
  439|      2|		return ret;
  440|      2|	}
  441|       |
  442|  2.02M|	return 0;
  443|  2.02M|}
__wrap_getaddrinfo:
  448|  1.65k|                       struct addrinfo **res) {
  449|       |	//printf("Wrapped getaddrinfo\n");
  450|       |
  451|  1.65k|	struct addrinfo default_hints = {};
  452|       |
  453|  1.65k|	if (!hints) {
  ------------------
  |  Branch (453:6): [True: 0, False: 1.65k]
  ------------------
  454|      0|		hints = &default_hints;
  455|      0|	}
  456|       |
  457|  1.65k|	unsigned char b;
  458|  1.65k|	if (consume_byte(&b)) {
  ------------------
  |  Branch (458:6): [True: 0, False: 1.65k]
  ------------------
  459|      0|		return -1;
  460|      0|	}
  461|       |
  462|       |	/* This one should be thread_local */
  463|  1.65k|	static /*thread_local*/ struct addrinfo ai;
  464|  1.65k|	ai.ai_flags = hints->ai_flags;
  465|  1.65k|	ai.ai_socktype = hints->ai_socktype;
  466|  1.65k|	ai.ai_protocol = hints->ai_protocol;
  467|       |
  468|  1.65k|	if (b > 127) {
  ------------------
  |  Branch (468:6): [True: 723, False: 932]
  ------------------
  469|    723|		ai.ai_family = AF_INET;//hints->ai_family;
  470|    932|	} else {
  471|    932|		ai.ai_family = AF_INET6;//hints->ai_family;
  472|    932|	}
  473|       |
  474|       |	/* This one is for generating the wrong family (maybe invalid?) */
  475|  1.65k|	if (b == 0) {
  ------------------
  |  Branch (475:6): [True: 1, False: 1.65k]
  ------------------
  476|      1|		ai.ai_family = hints->ai_family;
  477|      1|	}
  478|       |
  479|  1.65k|	ai.ai_next = NULL;
  480|  1.65k|	ai.ai_canonname = NULL; // fel
  481|       |
  482|       |	// these should depend on inet6 or inet */
  483|  1.65k|	ai.ai_addrlen = 4; // fel
  484|  1.65k|	ai.ai_addr = NULL; // ska peka på en sockaddr!
  485|       |
  486|       |	// we need to return an addrinfo with family AF_INET6
  487|       |
  488|  1.65k|	*res = &ai;
  489|  1.65k|	return 0;
  490|  1.65k|}
__wrap_freeaddrinfo:
  492|  1.65k|int __wrap_freeaddrinfo() {
  493|  1.65k|	return 0;
  494|  1.65k|}
__wrap_accept4:
  521|  3.02M|int __wrap_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
  522|       |	/* We must end with -1 since we are called in a loop */
  523|       |
  524|  3.02M|	unsigned char b;
  525|  3.02M|	if (consume_byte(&b)) {
  ------------------
  |  Branch (525:6): [True: 953, False: 3.02M]
  ------------------
  526|    953|		return -1;
  527|    953|	}
  528|       |
  529|       |	/* This rule might change, anything below 10 is accepted */
  530|  3.02M|	if (b < 10) {
  ------------------
  |  Branch (530:6): [True: 1.01M, False: 2.01M]
  ------------------
  531|       |
  532|  1.01M|		int fd = allocate_fd();
  533|  1.01M|		if (fd != -1) {
  ------------------
  |  Branch (533:7): [True: 1.01M, False: 422]
  ------------------
  534|       |
  535|       |			/* Allocate the file */
  536|  1.01M|			struct socket_file *sf = (struct socket_file *) malloc(sizeof(struct socket_file));
  537|       |
  538|       |			/* Init the file */
  539|       |
  540|       |			/* Here we need to create a socket FD and return */
  541|  1.01M|			init_fd(fd, FD_TYPE_SOCKET, (struct file *)sf);
  542|       |
  543|       |			/* We need to provide an addr */
  544|       |
  545|       |			/* Begin by setting it to an empty in6 address */
  546|  1.01M|			memset(&sf->addr, 0, sizeof(struct sockaddr_in6));
  547|  1.01M|			sf->len = sizeof(struct sockaddr_in6);
  548|  1.01M|			sf->addr.in6.sin6_family = AF_INET6;
  549|       |
  550|       |			/* Opt-in to ipv4 */
  551|  1.01M|			if (b < 5) {
  ------------------
  |  Branch (551:8): [True: 451k, False: 558k]
  ------------------
  552|   451k|				memset(&sf->addr, 0, sizeof(struct sockaddr_in6));
  553|   451k|				sf->len = sizeof(struct sockaddr_in);
  554|   451k|				sf->addr.in.sin_family = AF_INET;
  555|   451k|			}
  556|       |
  557|  1.01M|			if (addr) {
  ------------------
  |  Branch (557:8): [True: 1.01M, False: 0]
  ------------------
  558|       |				/* Copy from socket to addr */
  559|  1.01M|				memcpy(addr, &sf->addr, sf->len);
  560|  1.01M|			}
  561|  1.01M|		}
  562|       |
  563|  1.01M|		return fd;
  564|  1.01M|	}
  565|       |
  566|  2.01M|	return -1;
  567|  3.02M|}
__wrap_listen:
  569|  1.65k|int __wrap_listen() {
  570|       |	/* Listen consumes one byte and fails on -1 */
  571|  1.65k|	unsigned char b;
  572|  1.65k|	if (consume_byte(&b)) {
  ------------------
  |  Branch (572:6): [True: 10, False: 1.64k]
  ------------------
  573|     10|		return -1;
  574|     10|	}
  575|       |
  576|  1.64k|	if (b) {
  ------------------
  |  Branch (576:6): [True: 1.64k, False: 1]
  ------------------
  577|  1.64k|		return 0;
  578|  1.64k|	}
  579|       |
  580|      1|	return -1;
  581|  1.64k|}
__wrap_socket:
  584|  1.65k|int __wrap_socket(int domain, int type, int protocol) {
  585|       |
  586|       |	/* Only accept valid families */
  587|  1.65k|	if (domain != AF_INET && domain != AF_INET6) {
  ------------------
  |  Branch (587:6): [True: 931, False: 723]
  |  Branch (587:27): [True: 0, False: 931]
  ------------------
  588|      0|		return -1;
  589|      0|	}
  590|       |
  591|  1.65k|	int fd = allocate_fd();
  592|       |
  593|  1.65k|	if (fd != -1) {
  ------------------
  |  Branch (593:6): [True: 1.65k, False: 0]
  ------------------
  594|  1.65k|		struct socket_file *sf = (struct socket_file *)malloc(sizeof(struct socket_file));
  595|       |
  596|       |		/* Init the file */
  597|       |
  598|  1.65k|		init_fd(fd, FD_TYPE_SOCKET, (struct file *)sf);
  599|  1.65k|	}
  600|       |
  601|       |#ifdef PRINTF_DEBUG
  602|       |	printf("socket returning fd: %d\n", fd);
  603|       |#endif
  604|       |
  605|  1.65k|	return fd;
  606|  1.65k|}
__wrap_shutdown:
  608|  90.8k|int __wrap_shutdown() {
  609|       |	//printf("Wrapped shutdown\n");
  610|  90.8k|	return 0;
  611|  90.8k|}
__wrap_timerfd_create:
  619|  3.31k|int __wrap_timerfd_create(int clockid, int flags) {
  620|       |
  621|  3.31k|	int fd = allocate_fd();
  622|       |
  623|  3.31k|	if (fd != -1) {
  ------------------
  |  Branch (623:6): [True: 3.31k, False: 0]
  ------------------
  624|  3.31k|		struct timer_file *tf = (struct timer_file *)malloc(sizeof(struct timer_file));
  625|       |
  626|       |		/* Init the file */
  627|       |
  628|       |
  629|  3.31k|		init_fd(fd, FD_TYPE_TIMER, (struct file *)tf);
  630|       |
  631|  3.31k|	}
  632|       |
  633|       |#ifdef PRINTF_DEBUG
  634|       |	printf("timerfd_create returning fd: %d\n", fd);
  635|       |#endif
  636|       |
  637|  3.31k|	return fd;
  638|  3.31k|}
__wrap_timerfd_settime:
  642|  3.31k|                    struct itimerspec *old_value) {
  643|       |	//printf("timerfd_settime: %d\n", fd);
  644|  3.31k|	return 0;
  645|  3.31k|}
__wrap_eventfd:
  653|  1.65k|int __wrap_eventfd() {
  654|       |
  655|  1.65k|	int fd = allocate_fd();
  656|       |
  657|  1.65k|	if (fd != -1) {
  ------------------
  |  Branch (657:6): [True: 1.65k, False: 0]
  ------------------
  658|  1.65k|		struct event_file *ef = (struct event_file *)malloc(sizeof(struct event_file));
  659|       |
  660|       |		/* Init the file */
  661|       |
  662|  1.65k|		init_fd(fd, FD_TYPE_EVENT, (struct file *)ef);
  663|       |
  664|       |		//printf("eventfd: %d\n", fd);
  665|  1.65k|	}
  666|       |
  667|       |#ifdef PRINTF_DEBUG
  668|       |	printf("eventfd returning fd: %d\n", fd);
  669|       |#endif
  670|       |
  671|  1.65k|	return fd;
  672|  1.65k|}
__wrap_close:
  678|  1.01M|int __wrap_close(int fd) {
  679|       |
  680|  1.01M|	if (fd < RESERVED_SYSTEM_FDS) {
  ------------------
  |  Branch (680:6): [True: 0, False: 1.01M]
  ------------------
  681|      0|		return __real_close(fd);
  682|      0|	}
  683|       |
  684|  1.01M|	struct file *f = map_fd(fd);
  685|       |
  686|  1.01M|	if (!f) {
  ------------------
  |  Branch (686:6): [True: 0, False: 1.01M]
  ------------------
  687|      0|		return -1;
  688|      0|	}
  689|       |
  690|  1.01M|	if (f->type == FD_TYPE_EPOLL) {
  ------------------
  |  Branch (690:6): [True: 1.65k, False: 1.01M]
  ------------------
  691|       |#ifdef PRINTF_DEBUG
  692|       |		printf("Closing epoll FD: %d\n", fd);
  693|       |#endif
  694|       |
  695|  1.65k|		free(f);
  696|       |
  697|  1.65k|		return free_fd(fd);
  698|       |
  699|  1.01M|	} else if (f->type == FD_TYPE_TIMER) {
  ------------------
  |  Branch (699:13): [True: 3.31k, False: 1.01M]
  ------------------
  700|       |#ifdef PRINTF_DEBUG
  701|       |		printf("Closing timer fd: %d\n", fd);
  702|       |#endif
  703|       |
  704|  3.31k|		free(f);
  705|       |
  706|  3.31k|		return free_fd(fd);
  707|  1.01M|	} else if (f->type == FD_TYPE_EVENT) {
  ------------------
  |  Branch (707:13): [True: 1.65k, False: 1.01M]
  ------------------
  708|       |#ifdef PRINTF_DEBUG
  709|       |		printf("Closing event fd: %d\n", fd);
  710|       |#endif
  711|       |
  712|  1.65k|		free(f);
  713|       |
  714|  1.65k|		return free_fd(fd);
  715|  1.01M|	} else if (f->type == FD_TYPE_SOCKET) {
  ------------------
  |  Branch (715:13): [True: 1.01M, False: 0]
  ------------------
  716|       |#ifdef PRINTF_DEBUG
  717|       |		printf("Closing socket fd: %d\n", fd);
  718|       |#endif
  719|       |
  720|       |		// we should call epoll_ctl remove here
  721|       |
  722|  1.01M|		free(f);
  723|       |
  724|  1.01M|		int ret = free_fd(fd);
  725|       |
  726|       |#ifdef PRINTF_DEBUG
  727|       |		printf("Ret: %d\n", ret);
  728|       |#endif
  729|       |
  730|       |		//free(-1);
  731|  1.01M|		return ret;
  732|  1.01M|	}
  733|       |
  734|      0|	return -1;
  735|  1.01M|}
LLVMFuzzerTestOneInput:
  737|  1.65k|int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
  738|  1.65k|	set_consumable_data(data, size);
  739|       |
  740|  1.65k|	test();
  741|       |
  742|  1.65k|	if (num_fds) {
  ------------------
  |  Branch (742:6): [True: 0, False: 1.65k]
  ------------------
  743|      0|		printf("ERROR! Cannot leave open FDs after test!\n");
  744|      0|	}
  745|       |
  746|  1.65k|	return 0;
  747|  1.65k|}

