LLVMFuzzerTestOneInput:
   76|  3.33k|extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
   77|       |    /* Create parser */
   78|  3.33k|    uWS::HttpParser httpParser;
   79|       |    /* User data */
   80|  3.33k|    void *user = (void *) 13;
   81|       |
   82|       |    /* If we are built with WITH_PROXY, pass a ProxyParser as reserved */
   83|  3.33k|    void *reserved = nullptr;
   84|  3.33k|#ifdef UWS_WITH_PROXY
   85|  3.33k|    uWS::ProxyParser pp;
   86|  3.33k|    reserved = (void *) &pp;
   87|  3.33k|#endif
   88|       |
   89|       |    /* Iterate the padded fuzz as chunks */
   90|  3.33k|    makeChunked(makePadded(data, size), size, [&httpParser, &user, reserved](const uint8_t *data, size_t size) {
   91|       |        /* We need at least 1 byte post padding */
   92|  3.33k|        if (size) {
   93|  3.33k|            size--;
   94|  3.33k|        } else {
   95|       |            /* We might be given zero length chunks */
   96|  3.33k|            return;
   97|  3.33k|        }
   98|       |
   99|       |        /* If user is null then ignore this chunk */
  100|  3.33k|        if (!user) {
  101|  3.33k|            return;
  102|  3.33k|        }
  103|       |
  104|       |        /* Parse it */
  105|  3.33k|        auto [err, returnedUser] = httpParser.consumePostPadded((char *) data, size, user, reserved, [reserved](void *s, uWS::HttpRequest *httpRequest) -> void * {
  106|       |
  107|  3.33k|            readBytes(httpRequest->getHeader(httpRequest->getUrl()));
  108|  3.33k|            readBytes(httpRequest->getMethod());
  109|  3.33k|            readBytes(httpRequest->getQuery());
  110|  3.33k|            readBytes(httpRequest->getQuery("hello"));
  111|  3.33k|            readBytes(httpRequest->getQuery(""));
  112|       |            //readBytes(httpRequest->getParameter(0));
  113|       |
  114|  3.33k|#ifdef UWS_WITH_PROXY
  115|  3.33k|            auto *pp = (uWS::ProxyParser *) reserved;
  116|  3.33k|            readBytes(pp->getSourceAddress());
  117|  3.33k|#endif
  118|       |
  119|       |            /* Route the method and URL in two passes */
  120|  3.33k|            staticData.router.getUserData() = {};
  121|  3.33k|            if (!staticData.router.route(httpRequest->getMethod(), httpRequest->getUrl())) {
  122|       |                /* It was not handled */
  123|  3.33k|                return nullptr;
  124|  3.33k|            }
  125|       |
  126|  3.33k|            for (auto p : *httpRequest) {
  127|       |
  128|  3.33k|            }
  129|       |
  130|       |            /* Return ok */
  131|  3.33k|            return s;
  132|       |
  133|  3.33k|        }, [](void *user, std::string_view data, bool fin) -> void * {
  134|       |
  135|       |            /* Return ok */
  136|  3.33k|            return user;
  137|       |
  138|  3.33k|        });
  139|       |
  140|  3.33k|        if (!returnedUser) {
  141|       |            /* It is of uttermost importance that if and when we return nullptr from the httpParser we must not
  142|       |             * ever use the httpParser ever again. It is in a broken state as returning nullptr is only used
  143|       |             * for signalling early closure. You must absolutely must throw it away. Here we just mark user as
  144|       |             * null so that we can ignore further chunks of data */
  145|  3.33k|            user = nullptr;
  146|  3.33k|        }
  147|  3.33k|    });
  148|       |
  149|  3.33k|    return 0;
  150|  3.33k|}
_ZN10StaticDataC2Ev:
   24|      2|    StaticData() {
   25|       |
   26|      2|        router.add({"get"}, "/:hello/:hi", [](auto *h) mutable {
   27|      2|            auto [paramsTop, params] = h->getParameters();
   28|       |
   29|       |            /* Something is horribly wrong */
   30|      2|            if (paramsTop != 1 || !params[0].length() || !params[1].length()) {
   31|      2|                exit(-1);
   32|      2|            }
   33|       |
   34|       |            /* This route did handle it */
   35|      2|            return true;
   36|      2|        });
   37|       |
   38|      2|        router.add({"post"}, "/:hello/:hi/*", [](auto *h) mutable {
   39|      2|            auto [paramsTop, params] = h->getParameters();
   40|       |
   41|       |            /* Something is horribly wrong */
   42|      2|            if (paramsTop != 1 || !params[0].length() || !params[1].length()) {
   43|      2|                exit(-1);
   44|      2|            }
   45|       |
   46|       |            /* This route did handle it */
   47|      2|            return true;
   48|      2|        });
   49|       |
   50|      2|        router.add({"get"}, "/*", [](auto *h) mutable {
   51|      2|            auto [paramsTop, params] = h->getParameters();
   52|       |
   53|       |            /* Something is horribly wrong */
   54|      2|            if (paramsTop != -1) {
   55|      2|                exit(-1);
   56|      2|            }
   57|       |
   58|       |            /* This route did not handle it */
   59|      2|            return false;
   60|      2|        });
   61|       |
   62|      2|        router.add({"get"}, "/hi", [](auto *h) mutable {
   63|      2|            auto [paramsTop, params] = h->getParameters();
   64|       |
   65|       |            /* Something is horribly wrong */
   66|      2|            if (paramsTop != -1) {
   67|      2|                exit(-1);
   68|      2|            }
   69|       |
   70|       |            /* This route did handle it */
   71|      2|            return true;
   72|      2|        });
   73|      2|    }
_ZZN10StaticDataC1EvENUlPT_E_clIN3uWS10HttpRouterINS_10RouterDataEEEEEDaS1_:
   26|  3.53k|        router.add({"get"}, "/:hello/:hi", [](auto *h) mutable {
   27|  3.53k|            auto [paramsTop, params] = h->getParameters();
   28|       |
   29|       |            /* Something is horribly wrong */
   30|  3.53k|            if (paramsTop != 1 || !params[0].length() || !params[1].length()) {
  ------------------
  |  Branch (30:17): [True: 0, False: 3.53k]
  |  Branch (30:35): [True: 0, False: 3.53k]
  |  Branch (30:58): [True: 0, False: 3.53k]
  ------------------
   31|      0|                exit(-1);
   32|      0|            }
   33|       |
   34|       |            /* This route did handle it */
   35|  3.53k|            return true;
   36|  3.53k|        });
_ZZN10StaticDataC1EvENUlPT_E0_clIN3uWS10HttpRouterINS_10RouterDataEEEEEDaS1_:
   38|  1.13k|        router.add({"post"}, "/:hello/:hi/*", [](auto *h) mutable {
   39|  1.13k|            auto [paramsTop, params] = h->getParameters();
   40|       |
   41|       |            /* Something is horribly wrong */
   42|  1.13k|            if (paramsTop != 1 || !params[0].length() || !params[1].length()) {
  ------------------
  |  Branch (42:17): [True: 0, False: 1.13k]
  |  Branch (42:35): [True: 0, False: 1.13k]
  |  Branch (42:58): [True: 0, False: 1.13k]
  ------------------
   43|      0|                exit(-1);
   44|      0|            }
   45|       |
   46|       |            /* This route did handle it */
   47|  1.13k|            return true;
   48|  1.13k|        });
_ZZN10StaticDataC1EvENUlPT_E1_clIN3uWS10HttpRouterINS_10RouterDataEEEEEDaS1_:
   50|    117|        router.add({"get"}, "/*", [](auto *h) mutable {
   51|    117|            auto [paramsTop, params] = h->getParameters();
   52|       |
   53|       |            /* Something is horribly wrong */
   54|    117|            if (paramsTop != -1) {
  ------------------
  |  Branch (54:17): [True: 0, False: 117]
  ------------------
   55|      0|                exit(-1);
   56|      0|            }
   57|       |
   58|       |            /* This route did not handle it */
   59|    117|            return false;
   60|    117|        });
_ZZN10StaticDataC1EvENUlPT_E2_clIN3uWS10HttpRouterINS_10RouterDataEEEEEDaS1_:
   62|  9.33k|        router.add({"get"}, "/hi", [](auto *h) mutable {
   63|  9.33k|            auto [paramsTop, params] = h->getParameters();
   64|       |
   65|       |            /* Something is horribly wrong */
   66|  9.33k|            if (paramsTop != -1) {
  ------------------
  |  Branch (66:17): [True: 0, False: 9.33k]
  ------------------
   67|      0|                exit(-1);
   68|      0|            }
   69|       |
   70|       |            /* This route did handle it */
   71|  9.33k|            return true;
   72|  9.33k|        });
Http.cpp:_ZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhm:
   90|   111k|    makeChunked(makePadded(data, size), size, [&httpParser, &user, reserved](const uint8_t *data, size_t size) {
   91|       |        /* We need at least 1 byte post padding */
   92|   111k|        if (size) {
  ------------------
  |  Branch (92:13): [True: 111k, False: 22]
  ------------------
   93|   111k|            size--;
   94|   111k|        } else {
   95|       |            /* We might be given zero length chunks */
   96|     22|            return;
   97|     22|        }
   98|       |
   99|       |        /* If user is null then ignore this chunk */
  100|   111k|        if (!user) {
  ------------------
  |  Branch (100:13): [True: 259, False: 111k]
  ------------------
  101|    259|            return;
  102|    259|        }
  103|       |
  104|       |        /* Parse it */
  105|   111k|        auto [err, returnedUser] = httpParser.consumePostPadded((char *) data, size, user, reserved, [reserved](void *s, uWS::HttpRequest *httpRequest) -> void * {
  106|       |
  107|   111k|            readBytes(httpRequest->getHeader(httpRequest->getUrl()));
  108|   111k|            readBytes(httpRequest->getMethod());
  109|   111k|            readBytes(httpRequest->getQuery());
  110|   111k|            readBytes(httpRequest->getQuery("hello"));
  111|   111k|            readBytes(httpRequest->getQuery(""));
  112|       |            //readBytes(httpRequest->getParameter(0));
  113|       |
  114|   111k|#ifdef UWS_WITH_PROXY
  115|   111k|            auto *pp = (uWS::ProxyParser *) reserved;
  116|   111k|            readBytes(pp->getSourceAddress());
  117|   111k|#endif
  118|       |
  119|       |            /* Route the method and URL in two passes */
  120|   111k|            staticData.router.getUserData() = {};
  121|   111k|            if (!staticData.router.route(httpRequest->getMethod(), httpRequest->getUrl())) {
  122|       |                /* It was not handled */
  123|   111k|                return nullptr;
  124|   111k|            }
  125|       |
  126|   111k|            for (auto p : *httpRequest) {
  127|       |
  128|   111k|            }
  129|       |
  130|       |            /* Return ok */
  131|   111k|            return s;
  132|       |
  133|   111k|        }, [](void *user, std::string_view data, bool fin) -> void * {
  134|       |
  135|       |            /* Return ok */
  136|   111k|            return user;
  137|       |
  138|   111k|        });
  139|       |
  140|   111k|        if (!returnedUser) {
  ------------------
  |  Branch (140:13): [True: 778, False: 110k]
  ------------------
  141|       |            /* It is of uttermost importance that if and when we return nullptr from the httpParser we must not
  142|       |             * ever use the httpParser ever again. It is in a broken state as returning nullptr is only used
  143|       |             * for signalling early closure. You must absolutely must throw it away. Here we just mark user as
  144|       |             * null so that we can ignore further chunks of data */
  145|    778|            user = nullptr;
  146|    778|        }
  147|   111k|    });
Http.cpp:_ZZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmENKUlPvPN3uWS11HttpRequestEE_clES2_S5_:
  105|  14.7k|        auto [err, returnedUser] = httpParser.consumePostPadded((char *) data, size, user, reserved, [reserved](void *s, uWS::HttpRequest *httpRequest) -> void * {
  106|       |
  107|  14.7k|            readBytes(httpRequest->getHeader(httpRequest->getUrl()));
  108|  14.7k|            readBytes(httpRequest->getMethod());
  109|  14.7k|            readBytes(httpRequest->getQuery());
  110|  14.7k|            readBytes(httpRequest->getQuery("hello"));
  111|  14.7k|            readBytes(httpRequest->getQuery(""));
  112|       |            //readBytes(httpRequest->getParameter(0));
  113|       |
  114|  14.7k|#ifdef UWS_WITH_PROXY
  115|  14.7k|            auto *pp = (uWS::ProxyParser *) reserved;
  116|  14.7k|            readBytes(pp->getSourceAddress());
  117|  14.7k|#endif
  118|       |
  119|       |            /* Route the method and URL in two passes */
  120|  14.7k|            staticData.router.getUserData() = {};
  121|  14.7k|            if (!staticData.router.route(httpRequest->getMethod(), httpRequest->getUrl())) {
  ------------------
  |  Branch (121:17): [True: 778, False: 13.9k]
  ------------------
  122|       |                /* It was not handled */
  123|    778|                return nullptr;
  124|    778|            }
  125|       |
  126|  28.3k|            for (auto p : *httpRequest) {
  ------------------
  |  Branch (126:25): [True: 28.3k, False: 13.9k]
  ------------------
  127|       |
  128|  28.3k|            }
  129|       |
  130|       |            /* Return ok */
  131|  13.9k|            return s;
  132|       |
  133|  14.7k|        }, [](void *user, std::string_view data, bool fin) -> void * {
Http.cpp:_ZZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmENKUlPvNSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbE_clES2_S7_b:
  133|  39.4k|        }, [](void *user, std::string_view data, bool fin) -> void * {
  134|       |
  135|       |            /* Return ok */
  136|  39.4k|            return user;
  137|       |
  138|  39.4k|        });

Http.cpp:_ZL11makeChunkedPKhmNSt3__18functionIFvS0_mEEE:
   28|  3.33k|static inline void makeChunked(const uint8_t *data, size_t size, std::function<void(const uint8_t *data, size_t size)> cb) {
   29|       |    /* First byte determines chunk size; 0 is all that remains, 1-255 is small chunk */
   30|   115k|    for (int i = 0; i < size; ) {
  ------------------
  |  Branch (30:21): [True: 111k, False: 3.33k]
  ------------------
   31|   111k|        unsigned int chunkSize = data[i++];
   32|   111k|        if (!chunkSize) {
  ------------------
  |  Branch (32:13): [True: 1.44k, False: 110k]
  ------------------
   33|  1.44k|            chunkSize = size - i;
   34|   110k|        } else {
   35|   110k|            chunkSize = std::min<int>(chunkSize, size - i);
   36|   110k|        }
   37|       |
   38|   111k|        cb(data + i, chunkSize);
   39|   111k|        i += chunkSize;
   40|   111k|    }
   41|  3.33k|}
Http.cpp:_ZL10makePaddedPKhm:
   11|  3.33k|static inline const uint8_t *makePadded(const uint8_t *data, size_t size) {
   12|  3.33k|    static int paddedLength = 512 * 1024;
   13|  3.33k|    static char *padded = new char[128 + paddedLength + 128];
   14|       |
   15|       |    /* Increase landing area if required */
   16|  3.33k|    if (paddedLength < size) {
  ------------------
  |  Branch (16:9): [True: 21, False: 3.31k]
  ------------------
   17|     21|        delete [] padded;
   18|     21|        paddedLength = size;
   19|     21|        padded = new char [128 + paddedLength + 128];
   20|     21|    }
   21|       |
   22|  3.33k|    memcpy(padded + 128, data, size);
   23|       |
   24|  3.33k|    return (uint8_t *) padded + 128;
   25|  3.33k|}
Http.cpp:_ZL9readBytesNSt3__117basic_string_viewIcNS_11char_traitsIcEEEE:
   44|  88.6k|static inline void readBytes(std::string_view s) {
   45|  88.6k|    volatile int sum = 0;
   46|  2.69M|    for (int i = 0; i < s.size(); i++) {
  ------------------
  |  Branch (46:21): [True: 2.60M, False: 88.6k]
  ------------------
   47|  2.60M|        sum += s[i];
   48|  2.60M|    }
   49|  88.6k|}

_ZN3uWS11BloomFilter5resetEv:
   76|  17.1k|    void reset() {
   77|  17.1k|        filter.reset();
   78|  17.1k|    }
_ZN3uWS11BloomFilter9mightHaveENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
   52|  99.6k|    bool mightHave(std::string_view key) {
   53|  99.6k|        if (key.length() < 2) {
  ------------------
  |  Branch (53:13): [True: 2.67k, False: 96.9k]
  ------------------
   54|  2.67k|            return true;
   55|  2.67k|        }
   56|       |    
   57|  96.9k|        ScrambleArea s = getFeatures(key);
   58|  96.9k|        s.val = perfectHash(s.val);
   59|  96.9k|        return filter[s.p[0]] &&
  ------------------
  |  Branch (59:16): [True: 32.1k, False: 64.7k]
  ------------------
   60|  96.9k|        filter[s.p[1]] &&
  ------------------
  |  Branch (60:9): [True: 29.4k, False: 2.67k]
  ------------------
   61|  96.9k|        filter[s.p[2]] &&
  ------------------
  |  Branch (61:9): [True: 26.2k, False: 3.20k]
  ------------------
   62|  96.9k|        filter[s.p[3]];
  ------------------
  |  Branch (62:9): [True: 25.3k, False: 880]
  ------------------
   63|  99.6k|    }
_ZN3uWS11BloomFilter11getFeaturesENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
   42|   131k|    ScrambleArea getFeatures(std::string_view key) {
   43|   131k|        ScrambleArea s;
   44|   131k|        s.p[0] = reinterpret_cast<const unsigned char&>(key[0]);
   45|   131k|        s.p[1] = reinterpret_cast<const unsigned char&>(key[key.length() - 1]);
   46|   131k|        s.p[2] = reinterpret_cast<const unsigned char&>(key[key.length() - 2]);
   47|   131k|        s.p[3] = reinterpret_cast<const unsigned char&>(key[key.length() >> 1]);
   48|   131k|        return s;
   49|   131k|    }
_ZN3uWS11BloomFilter11perfectHashEj:
   33|   131k|    static inline uint32_t perfectHash(uint32_t features) {
   34|   131k|        return features * 1843993368;
   35|   131k|    }
_ZN3uWS11BloomFilter3addENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
   65|  36.7k|    void add(std::string_view key) {
   66|  36.7k|        if (key.length() >= 2) {
  ------------------
  |  Branch (66:13): [True: 34.6k, False: 2.07k]
  ------------------
   67|  34.6k|            ScrambleArea s = getFeatures(key);
   68|  34.6k|            s.val = perfectHash(s.val);
   69|  34.6k|            filter[s.p[0]] = 1;
   70|  34.6k|            filter[s.p[1]] = 1;
   71|  34.6k|            filter[s.p[2]] = 1;
   72|  34.6k|            filter[s.p[3]] = 1;
   73|  34.6k|        }
   74|  36.7k|    }

_ZN3uWS24isParsingChunkedEncodingEm:
   95|  26.9k|    inline bool isParsingChunkedEncoding(uint64_t state) {
   96|  26.9k|        return state & ~STATE_SIZE_MASK;
   97|  26.9k|    }
_ZN3uWS13ChunkIteratorC2EPNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPmb:
  201|  27.1k|        ChunkIterator(std::string_view *data, uint64_t *state, bool trailer = false) : data(data), state(state), trailer(trailer) {
  202|  27.1k|            chunk = uWS::getNextChunk(*data, *state, trailer);
  203|  27.1k|        }
Http.cpp:_ZN3uWSL12getNextChunkERNSt3__117basic_string_viewIcNS0_11char_traitsIcEEEERmb:
  104|  54.3k|    static std::optional<std::string_view> getNextChunk(std::string_view &data, uint64_t &state, bool trailer = false) {
  105|       |
  106|  58.7k|        while (data.length()) {
  ------------------
  |  Branch (106:16): [True: 33.6k, False: 25.0k]
  ------------------
  107|       |
  108|       |            // if in "drop trailer mode", just drop up to what we have as size
  109|  33.6k|            if (((state & STATE_IS_CHUNKED) == 0) && hasChunkSize(state) && chunkSize(state)) {
  ------------------
  |  Branch (109:17): [True: 2.16k, False: 31.4k]
  |  Branch (109:54): [True: 2.16k, False: 0]
  |  Branch (109:77): [True: 2.16k, False: 0]
  ------------------
  110|       |
  111|       |                //printf("Parsing trailer now\n");
  112|       |
  113|  4.14k|                while(data.length() && chunkSize(state)) {
  ------------------
  |  Branch (113:23): [True: 3.94k, False: 201]
  |  Branch (113:40): [True: 3.94k, False: 0]
  ------------------
  114|  3.94k|                    data.remove_prefix(1);
  115|  3.94k|                    decChunkSize(state, 1);
  116|       |
  117|  3.94k|                    if (chunkSize(state) == 0) {
  ------------------
  |  Branch (117:25): [True: 1.96k, False: 1.97k]
  ------------------
  118|       |
  119|       |                        /* This is an actual place where we need 0 as state */
  120|  1.96k|                        state = 0;
  121|       |
  122|       |                        /* The parser MUST stop consuming here */
  123|  1.96k|                        return std::nullopt;
  124|  1.96k|                    }
  125|  3.94k|                }
  126|    201|                continue;
  127|  2.16k|            }
  128|       |
  129|  31.4k|            if (!hasChunkSize(state)) {
  ------------------
  |  Branch (129:17): [True: 5.98k, False: 25.4k]
  ------------------
  130|  5.98k|                consumeHexNumber(data, state);
  131|  5.98k|                if (isParsingInvalidChunkedEncoding(state)) {
  ------------------
  |  Branch (131:21): [True: 54, False: 5.93k]
  ------------------
  132|     54|                    return std::nullopt;
  133|     54|                }
  134|  5.93k|                if (hasChunkSize(state) && chunkSize(state) == 2) {
  ------------------
  |  Branch (134:21): [True: 4.70k, False: 1.22k]
  |  Branch (134:44): [True: 2.03k, False: 2.67k]
  ------------------
  135|       |
  136|       |                    //printf("Setting state to trailer-parsing and emitting empty chunk\n");
  137|       |
  138|       |                    // set trailer state and increase size to 4
  139|  2.03k|                    if (trailer) {
  ------------------
  |  Branch (139:25): [True: 0, False: 2.03k]
  ------------------
  140|      0|                        state = 4 /*| STATE_IS_CHUNKED*/ | STATE_HAS_SIZE;
  141|  2.03k|                    } else {
  142|  2.03k|                        state = 2 /*| STATE_IS_CHUNKED*/ | STATE_HAS_SIZE;
  143|  2.03k|                    }
  144|       |
  145|  2.03k|                    return std::string_view(nullptr, 0);
  146|  2.03k|                }
  147|  3.89k|                continue;
  148|  5.93k|            }
  149|       |
  150|       |            // do we have data to emit all?
  151|  25.4k|            if (data.length() >= chunkSize(state)) {
  ------------------
  |  Branch (151:17): [True: 2.42k, False: 23.0k]
  ------------------
  152|       |                // emit all but 2 bytes then reset state to 0 and goto beginning
  153|       |                // not fin
  154|  2.42k|                std::string_view emitSoon;
  155|  2.42k|                bool shouldEmit = false;
  156|  2.42k|                if (chunkSize(state) > 2) {
  ------------------
  |  Branch (156:21): [True: 2.14k, False: 278]
  ------------------
  157|  2.14k|                    emitSoon = std::string_view(data.data(), chunkSize(state) - 2);
  158|  2.14k|                    shouldEmit = true;
  159|  2.14k|                }
  160|  2.42k|                data.remove_prefix(chunkSize(state));
  161|  2.42k|                state = STATE_IS_CHUNKED;
  162|  2.42k|                if (shouldEmit) {
  ------------------
  |  Branch (162:21): [True: 2.14k, False: 278]
  ------------------
  163|  2.14k|                    return emitSoon;
  164|  2.14k|                }
  165|    278|                continue;
  166|  23.0k|            } else {
  167|       |                /* We will consume all our input data */
  168|  23.0k|                std::string_view emitSoon;
  169|  23.0k|                if (chunkSize(state) > 2) {
  ------------------
  |  Branch (169:21): [True: 23.0k, False: 1]
  ------------------
  170|  23.0k|                    uint64_t maximalAppEmit = chunkSize(state) - 2;
  171|  23.0k|                    if (data.length() > maximalAppEmit) {
  ------------------
  |  Branch (171:25): [True: 247, False: 22.8k]
  ------------------
  172|    247|                        emitSoon = data.substr(0, maximalAppEmit);
  173|  22.8k|                    } else {
  174|       |                        //cb(data);
  175|  22.8k|                        emitSoon = data;
  176|  22.8k|                    }
  177|  23.0k|                }
  178|  23.0k|                decChunkSize(state, (unsigned int) data.length());
  179|  23.0k|                state |= STATE_IS_CHUNKED;
  180|       |                // new: decrease data by its size (bug)
  181|  23.0k|                data.remove_prefix(data.length()); // ny bug fix för getNextChunk
  182|  23.0k|                if (emitSoon.length()) {
  ------------------
  |  Branch (182:21): [True: 23.0k, False: 1]
  ------------------
  183|  23.0k|                    return emitSoon;
  184|  23.0k|                } else {
  185|      1|                    return std::nullopt;
  186|      1|                }
  187|  23.0k|            }
  188|  25.4k|        }
  189|       |
  190|  25.0k|        return std::nullopt;
  191|  54.3k|    }
_ZN3uWS12hasChunkSizeEm:
   90|  39.5k|    inline bool hasChunkSize(uint64_t state) {
   91|  39.5k|        return state & STATE_HAS_SIZE;
   92|  39.5k|    }
_ZN3uWS9chunkSizeEm:
   38|   147k|    inline uint64_t chunkSize(uint64_t state) {
   39|   147k|        return state & STATE_SIZE_MASK;
   40|   147k|    }
_ZN3uWS12decChunkSizeERmj:
   81|  26.9k|    inline void decChunkSize(uint64_t &state, unsigned int by) {
   82|       |
   83|       |        //unsigned int bits = state & STATE_IS_CHUNKED;
   84|       |
   85|  26.9k|        state = (state & ~STATE_SIZE_MASK) | (chunkSize(state) - by);
   86|       |
   87|       |        //state |= bits;
   88|  26.9k|    }
_ZN3uWS16consumeHexNumberERNSt3__117basic_string_viewIcNS0_11char_traitsIcEEEERm:
   43|  5.98k|    inline void consumeHexNumber(std::string_view &data, uint64_t &state) {
   44|       |        /* Consume everything higher than 32 */
   45|  33.1k|        while (data.length() && data.data()[0] > 32) {
  ------------------
  |  Branch (45:16): [True: 32.7k, False: 432]
  |  Branch (45:33): [True: 27.2k, False: 5.49k]
  ------------------
   46|       |
   47|  27.2k|            unsigned char digit = (unsigned char)data.data()[0];
   48|  27.2k|            if (digit >= 'a') {
  ------------------
  |  Branch (48:17): [True: 2.27k, False: 24.9k]
  ------------------
   49|  2.27k|                digit = (unsigned char) (digit - ('a' - ':'));
   50|  24.9k|            } else if (digit >= 'A') {
  ------------------
  |  Branch (50:24): [True: 866, False: 24.0k]
  ------------------
   51|    866|                digit = (unsigned char) (digit - ('A' - ':'));
   52|    866|            }
   53|       |
   54|  27.2k|            unsigned int number = ((unsigned int) digit - (unsigned int) '0');
   55|       |
   56|  27.2k|            if (number > 16 || (chunkSize(state) & STATE_SIZE_OVERFLOW)) {
  ------------------
  |  Branch (56:17): [True: 47, False: 27.1k]
  |  Branch (56:32): [True: 7, False: 27.1k]
  ------------------
   57|     54|                state = STATE_IS_ERROR;
   58|     54|                return;
   59|     54|            }
   60|       |
   61|       |            // extract state bits
   62|  27.1k|            uint64_t bits = /*state &*/ STATE_IS_CHUNKED;
   63|       |
   64|  27.1k|            state = (state & STATE_SIZE_MASK) * 16ull + number;
   65|       |
   66|  27.1k|            state |= bits;
   67|  27.1k|            data.remove_prefix(1);
   68|  27.1k|        }
   69|       |        /* Consume everything not /n */
   70|   169k|        while (data.length() && data.data()[0] != '\n') {
  ------------------
  |  Branch (70:16): [True: 168k, False: 1.22k]
  |  Branch (70:33): [True: 163k, False: 4.70k]
  ------------------
   71|   163k|            data.remove_prefix(1);
   72|   163k|        }
   73|       |        /* Now we stand on \n so consume it and enable size */
   74|  5.93k|        if (data.length()) {
  ------------------
  |  Branch (74:13): [True: 4.70k, False: 1.22k]
  ------------------
   75|  4.70k|            state += 2; // include the two last /r/n
   76|  4.70k|            state |= STATE_HAS_SIZE | STATE_IS_CHUNKED;
   77|  4.70k|            data.remove_prefix(1);
   78|  4.70k|        }
   79|  5.93k|    }
_ZN3uWS13ChunkIterator5beginEv:
  209|  27.1k|        ChunkIterator begin() {
  210|  27.1k|            return *this;
  211|  27.1k|        }
_ZN3uWS13ChunkIterator3endEv:
  213|  27.1k|        ChunkIterator end() {
  214|  27.1k|            return ChunkIterator();
  215|  27.1k|        }
_ZN3uWS13ChunkIteratorC2Ev:
  205|  27.1k|        ChunkIterator() {
  206|       |
  207|  27.1k|        }
_ZNK3uWS13ChunkIteratorneERKS0_:
  224|  54.3k|        bool operator!=(const ChunkIterator &other) const {
  225|  54.3k|            return other.chunk.has_value() != chunk.has_value();
  226|  54.3k|        }
_ZN3uWS13ChunkIteratordeEv:
  217|  27.2k|        std::string_view operator*() {
  218|  27.2k|            if (!chunk.has_value()) {
  ------------------
  |  Branch (218:17): [True: 0, False: 27.2k]
  ------------------
  219|      0|                std::abort();
  220|      0|            }
  221|  27.2k|            return chunk.value();
  222|  27.2k|        }
_ZN3uWS13ChunkIteratorppEv:
  228|  27.2k|        ChunkIterator &operator++() {
  229|  27.2k|            chunk = uWS::getNextChunk(*data, *state, trailer);
  230|  27.2k|            return *this;
  231|  27.2k|        }
_ZN3uWS31isParsingInvalidChunkedEncodingEm:
   99|  33.1k|    inline bool isParsingInvalidChunkedEncoding(uint64_t state) {
  100|  33.1k|        return state == STATE_IS_ERROR;
  101|  33.1k|    }

_ZN3uWS12optional_ptrIcEENSt3__18optionalIPT_EES4_:
   47|      2|std::optional<T *> optional_ptr(T *ptr) {
   48|      2|    return ptr ? std::optional<T *>(ptr) : std::nullopt;
  ------------------
  |  Branch (48:12): [True: 0, False: 2]
  ------------------
   49|      2|}
_ZN3uWS10HttpParser17consumePostPaddedEPcjPvS2_ON5ofats13any_invocableIFS2_S2_PNS_11HttpRequestEEEEONS4_IFS2_S2_NSt3__117basic_string_viewIcNSA_11char_traitsIcEEEEbEEE:
  618|   111k|    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) {
  619|       |
  620|       |        /* This resets BloomFilter by construction, but later we also reset it again.
  621|       |         * Optimize this to skip resetting twice (req could be made global) */
  622|   111k|        HttpRequest req;
  623|       |
  624|   111k|        if (remainingStreamingBytes) {
  ------------------
  |  Branch (624:13): [True: 25.4k, False: 86.1k]
  ------------------
  625|       |
  626|       |            /* It's either chunked or with a content-length */
  627|  25.4k|            if (isParsingChunkedEncoding(remainingStreamingBytes)) {
  ------------------
  |  Branch (627:17): [True: 24.4k, False: 975]
  ------------------
  628|  24.4k|                std::string_view dataToConsume(data, length);
  629|  24.4k|                for (auto chunk : uWS::ChunkIterator(&dataToConsume, &remainingStreamingBytes)) {
  ------------------
  |  Branch (629:33): [True: 24.0k, False: 24.4k]
  ------------------
  630|  24.0k|                    dataHandler(user, chunk, chunk.length() == 0);
  631|  24.0k|                }
  632|  24.4k|                if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) {
  ------------------
  |  Branch (632:21): [True: 343, False: 24.1k]
  ------------------
  633|    343|                    return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  634|    343|                }
  635|  24.1k|                data = (char *) dataToConsume.data();
  636|  24.1k|                length = (unsigned int) dataToConsume.length();
  637|  24.1k|            } else {
  638|       |                // this is exactly the same as below!
  639|       |                // todo: refactor this
  640|    975|                if (remainingStreamingBytes >= length) {
  ------------------
  |  Branch (640:21): [True: 565, False: 410]
  ------------------
  641|    565|                    void *returnedUser = dataHandler(user, std::string_view(data, length), remainingStreamingBytes == length);
  642|    565|                    remainingStreamingBytes -= length;
  643|    565|                    return {0, returnedUser};
  644|    565|                } else {
  645|    410|                    void *returnedUser = dataHandler(user, std::string_view(data, remainingStreamingBytes), true);
  646|       |
  647|    410|                    data += (unsigned int) remainingStreamingBytes;
  648|    410|                    length -= (unsigned int) remainingStreamingBytes;
  649|       |
  650|    410|                    remainingStreamingBytes = 0;
  651|       |
  652|    410|                    if (returnedUser != user) {
  ------------------
  |  Branch (652:25): [True: 0, False: 410]
  ------------------
  653|      0|                        return {0, returnedUser};
  654|      0|                    }
  655|    410|                }
  656|    975|            }
  657|       |
  658|  86.1k|        } else if (fallback.length()) {
  ------------------
  |  Branch (658:20): [True: 38.2k, False: 47.9k]
  ------------------
  659|  38.2k|            unsigned int had = (unsigned int) fallback.length();
  660|       |
  661|  38.2k|            size_t maxCopyDistance = std::min<size_t>(MAX_FALLBACK_SIZE - fallback.length(), (size_t) length);
  662|       |
  663|       |            /* We don't want fallback to be short string optimized, since we want to move it */
  664|  38.2k|            fallback.reserve(fallback.length() + maxCopyDistance + std::max<unsigned int>(MINIMUM_HTTP_POST_PADDING, sizeof(std::string)));
  665|  38.2k|            fallback.append(data, maxCopyDistance);
  666|       |
  667|       |            // break here on break
  668|  38.2k|            std::pair<unsigned int, void *> consumed = fenceAndConsumePostPadded<true>(fallback.data(), (unsigned int) fallback.length(), user, reserved, &req, requestHandler, dataHandler);
  669|  38.2k|            if (consumed.second != user) {
  ------------------
  |  Branch (669:17): [True: 5.46k, False: 32.8k]
  ------------------
  670|  5.46k|                return consumed;
  671|  5.46k|            }
  672|       |
  673|  32.8k|            if (consumed.first) {
  ------------------
  |  Branch (673:17): [True: 2.21k, False: 30.6k]
  ------------------
  674|       |
  675|       |                /* This logic assumes that we consumed everything in fallback buffer.
  676|       |                 * This is critically important, as we will get an integer overflow in case
  677|       |                 * of "had" being larger than what we consumed, and that we would drop data */
  678|  2.21k|                fallback.clear();
  679|  2.21k|                data += consumed.first - had;
  680|  2.21k|                length -= consumed.first - had;
  681|       |
  682|  2.21k|                if (remainingStreamingBytes) {
  ------------------
  |  Branch (682:21): [True: 1.44k, False: 763]
  ------------------
  683|       |                    /* It's either chunked or with a content-length */
  684|  1.44k|                    if (isParsingChunkedEncoding(remainingStreamingBytes)) {
  ------------------
  |  Branch (684:25): [True: 738, False: 709]
  ------------------
  685|    738|                        std::string_view dataToConsume(data, length);
  686|    834|                        for (auto chunk : uWS::ChunkIterator(&dataToConsume, &remainingStreamingBytes)) {
  ------------------
  |  Branch (686:41): [True: 834, False: 738]
  ------------------
  687|    834|                            dataHandler(user, chunk, chunk.length() == 0);
  688|    834|                        }
  689|    738|                        if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) {
  ------------------
  |  Branch (689:29): [True: 27, False: 711]
  ------------------
  690|     27|                            return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  691|     27|                        }
  692|    711|                        data = (char *) dataToConsume.data();
  693|    711|                        length = (unsigned int) dataToConsume.length();
  694|    711|                    } else {
  695|       |                        // this is exactly the same as above!
  696|    709|                        if (remainingStreamingBytes >= (unsigned int) length) {
  ------------------
  |  Branch (696:29): [True: 435, False: 274]
  ------------------
  697|    435|                            void *returnedUser = dataHandler(user, std::string_view(data, length), remainingStreamingBytes == (unsigned int) length);
  698|    435|                            remainingStreamingBytes -= length;
  699|    435|                            return {0, returnedUser};
  700|    435|                        } else {
  701|    274|                            void *returnedUser = dataHandler(user, std::string_view(data, remainingStreamingBytes), true);
  702|       |
  703|    274|                            data += (unsigned int) remainingStreamingBytes;
  704|    274|                            length -= (unsigned int) remainingStreamingBytes;
  705|       |
  706|    274|                            remainingStreamingBytes = 0;
  707|       |
  708|    274|                            if (returnedUser != user) {
  ------------------
  |  Branch (708:33): [True: 0, False: 274]
  ------------------
  709|      0|                                return {0, returnedUser};
  710|      0|                            }
  711|    274|                        }
  712|    709|                    }
  713|  1.44k|                }
  714|       |
  715|  30.6k|            } else {
  716|  30.6k|                if (fallback.length() == MAX_FALLBACK_SIZE) {
  ------------------
  |  Branch (716:21): [True: 27.2k, False: 3.38k]
  ------------------
  717|  27.2k|                    return {HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE, FULLPTR};
  718|  27.2k|                }
  719|  3.38k|                return {0, user};
  720|  30.6k|            }
  721|  32.8k|        }
  722|       |
  723|  74.2k|        std::pair<unsigned int, void *> consumed = fenceAndConsumePostPadded<false>(data, length, user, reserved, &req, requestHandler, dataHandler);
  724|  74.2k|        if (consumed.second != user) {
  ------------------
  |  Branch (724:13): [True: 45.5k, False: 28.7k]
  ------------------
  725|  45.5k|            return consumed;
  726|  45.5k|        }
  727|       |
  728|  28.7k|        data += consumed.first;
  729|  28.7k|        length -= consumed.first;
  730|       |
  731|  28.7k|        if (length) {
  ------------------
  |  Branch (731:13): [True: 3.13k, False: 25.5k]
  ------------------
  732|  3.13k|            if (length < MAX_FALLBACK_SIZE) {
  ------------------
  |  Branch (732:17): [True: 3.09k, False: 47]
  ------------------
  733|  3.09k|                fallback.append(data, length);
  734|  3.09k|            } else {
  735|     47|                return {HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE, FULLPTR};
  736|     47|            }
  737|  3.13k|        }
  738|       |
  739|       |        // added for now
  740|  28.6k|        return {0, user};
  741|  28.7k|    }
_ZN3uWS10HttpParser25fenceAndConsumePostPaddedILi1EEENSt3__14pairIjPvEEPcjS4_S4_PNS_11HttpRequestERN5ofats13any_invocableIFS4_S4_S8_EEERNSA_IFS4_S4_NS2_17basic_string_viewIcNS2_11char_traitsIcEEEEbEEE:
  477|  38.2k|    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) {
  478|       |
  479|       |        /* How much data we CONSUMED (to throw away) */
  480|  38.2k|        unsigned int consumedTotal = 0;
  481|  38.2k|        unsigned int err = 0;
  482|       |
  483|       |        /* Fence two bytes past end of our buffer (buffer has post padded margins).
  484|       |         * This is to always catch scan for \r but not for \r\n. */
  485|  38.2k|        data[length] = '\r';
  486|  38.2k|        data[length + 1] = 'a'; /* Anything that is not \n, to trigger "invalid request" */
  487|       |
  488|  38.2k|        for (unsigned int consumed; length && (consumed = getHeaders(data, data + length, req->headers, reserved, err)); ) {
  ------------------
  |  Branch (488:37): [True: 38.2k, False: 0]
  |  Branch (488:47): [True: 3.93k, False: 34.3k]
  ------------------
  489|  3.93k|            data += consumed;
  490|  3.93k|            length -= consumed;
  491|  3.93k|            consumedTotal += consumed;
  492|       |
  493|       |            /* Even if we could parse it, check for length here as well */
  494|  3.93k|            if (consumed > MAX_FALLBACK_SIZE) {
  ------------------
  |  Branch (494:17): [True: 0, False: 3.93k]
  ------------------
  495|      0|                return {HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE, FULLPTR};
  496|      0|            }
  497|       |
  498|       |            /* Store HTTP version (ancient 1.0 or 1.1) */
  499|  3.93k|            req->ancientHttp = false;
  500|       |
  501|       |            /* Add all headers to bloom filter */
  502|  3.93k|            req->bf.reset();
  503|  13.8k|            for (HttpRequest::Header *h = req->headers; (++h)->key.length(); ) {
  ------------------
  |  Branch (503:57): [True: 10.1k, False: 3.72k]
  ------------------
  504|  10.1k|                if (req->bf.mightHave(h->key)) [[unlikely]] {
  ------------------
  |  Branch (504:21): [True: 1.56k, False: 8.60k]
  ------------------
  505|       |                    /* Host header is not allowed twice */
  506|  1.56k|                    if (h->key == "host" && req->getHeader("host").data()) {
  ------------------
  |  Branch (506:25): [True: 204, False: 1.36k]
  |  Branch (506:25): [True: 204, False: 1.36k]
  |  Branch (506:45): [True: 204, False: 0]
  ------------------
  507|    204|                        return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  508|    204|                    }
  509|  1.56k|                }
  510|  9.96k|                req->bf.add(h->key);
  511|  9.96k|            }
  512|       |            
  513|       |            /* Break if no host header (but we can have empty string which is different from nullptr) */
  514|  3.72k|            if (!req->getHeader("host").data()) {
  ------------------
  |  Branch (514:17): [True: 1.20k, False: 2.52k]
  ------------------
  515|  1.20k|                return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  516|  1.20k|            }
  517|       |
  518|       |            /* RFC 9112 6.3
  519|       |            * If a message is received with both a Transfer-Encoding and a Content-Length header field,
  520|       |            * the Transfer-Encoding overrides the Content-Length. Such a message might indicate an attempt
  521|       |            * to perform request smuggling (Section 11.2) or response splitting (Section 11.1) and
  522|       |            * ought to be handled as an error. */
  523|  2.52k|            std::string_view transferEncodingString = req->getHeader("transfer-encoding");
  524|  2.52k|            std::string_view contentLengthString = req->getHeader("content-length");
  525|  2.52k|            if (transferEncodingString.length() && contentLengthString.length()) {
  ------------------
  |  Branch (525:17): [True: 1.00k, False: 1.52k]
  |  Branch (525:52): [True: 258, False: 742]
  ------------------
  526|       |                /* Returning fullptr is the same as calling the errorHandler */
  527|       |                /* We could be smart and set an error in the context along with this, to indicate what 
  528|       |                 * http error response we might want to return */
  529|    258|                return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  530|    258|            }
  531|       |
  532|       |            /* Parse query */
  533|  2.26k|            const char *querySeparatorPtr = (const char *) memchr(req->headers->value.data(), '?', req->headers->value.length());
  534|  2.26k|            req->querySeparator = (unsigned int) ((querySeparatorPtr ? querySeparatorPtr : req->headers->value.data() + req->headers->value.length()) - req->headers->value.data());
  ------------------
  |  Branch (534:52): [True: 268, False: 2.00k]
  ------------------
  535|       |
  536|       |            /* If returned socket is not what we put in we need
  537|       |             * to break here as we either have upgraded to
  538|       |             * WebSockets or otherwise closed the socket. */
  539|  2.26k|            void *returnedUser = requestHandler(user, req);
  540|  2.26k|            if (returnedUser != user) {
  ------------------
  |  Branch (540:17): [True: 16, False: 2.25k]
  ------------------
  541|       |                /* We are upgraded to WebSocket or otherwise broken */
  542|     16|                return {consumedTotal, returnedUser};
  543|     16|            }
  544|       |
  545|       |            /* The rules at play here according to RFC 9112 for requests are essentially:
  546|       |             * If both content-length and transfer-encoding then invalid message; must break.
  547|       |             * If has transfer-encoding then must be chunked regardless of value.
  548|       |             * If content-length then fixed length even if 0.
  549|       |             * If none of the above then fixed length is 0. */
  550|       |
  551|       |            /* RFC 9112 6.3
  552|       |             * If a message is received with both a Transfer-Encoding and a Content-Length header field,
  553|       |             * the Transfer-Encoding overrides the Content-Length. */
  554|  2.25k|            if (transferEncodingString.length()) {
  ------------------
  |  Branch (554:17): [True: 738, False: 1.51k]
  ------------------
  555|       |
  556|       |                /* If a proxy sent us the transfer-encoding header that 100% means it must be chunked or else the proxy is
  557|       |                 * not RFC 9112 compliant. Therefore it is always better to assume this is the case, since that entirely eliminates 
  558|       |                 * all forms of transfer-encoding obfuscation tricks. We just rely on the header. */
  559|       |
  560|       |                /* RFC 9112 6.3
  561|       |                 * If a Transfer-Encoding header field is present in a request and the chunked transfer coding is not the
  562|       |                 * final encoding, the message body length cannot be determined reliably; the server MUST respond with the
  563|       |                 * 400 (Bad Request) status code and then close the connection. */
  564|       |
  565|       |                /* In this case we fail later by having the wrong interpretation (assuming chunked).
  566|       |                 * This could be made stricter but makes no difference either way, unless forwarding the identical message as a proxy. */
  567|       |
  568|    738|                remainingStreamingBytes = STATE_IS_CHUNKED;
  569|       |                /* If consume minimally, we do not want to consume anything but we want to mark this as being chunked */
  570|    738|                if (!CONSUME_MINIMALLY) {
  ------------------
  |  Branch (570:21): [Folded - Ignored]
  ------------------
  571|       |                    /* Go ahead and parse it (todo: better heuristics for emitting FIN to the app level) */
  572|      0|                    std::string_view dataToConsume(data, length);
  573|      0|                    for (auto chunk : uWS::ChunkIterator(&dataToConsume, &remainingStreamingBytes)) {
  ------------------
  |  Branch (573:37): [True: 0, False: 0]
  ------------------
  574|      0|                        dataHandler(user, chunk, chunk.length() == 0);
  575|      0|                    }
  576|      0|                    if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) {
  ------------------
  |  Branch (576:25): [True: 0, False: 0]
  ------------------
  577|      0|                        return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  578|      0|                    }
  579|      0|                    unsigned int consumed = (length - (unsigned int) dataToConsume.length());
  580|      0|                    data = (char *) dataToConsume.data();
  581|      0|                    length = (unsigned int) dataToConsume.length();
  582|      0|                    consumedTotal += consumed;
  583|      0|                }
  584|  1.51k|            } else if (contentLengthString.length()) {
  ------------------
  |  Branch (584:24): [True: 765, False: 749]
  ------------------
  585|    765|                remainingStreamingBytes = toUnsignedInteger(contentLengthString);
  586|    765|                if (remainingStreamingBytes == UINT64_MAX) {
  ------------------
  |  Branch (586:21): [True: 42, False: 723]
  ------------------
  587|       |                    /* Parser error */
  588|     42|                    return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  589|     42|                }
  590|       |
  591|    723|                if (!CONSUME_MINIMALLY) {
  ------------------
  |  Branch (591:21): [Folded - Ignored]
  ------------------
  592|      0|                    unsigned int emittable = (unsigned int) std::min<uint64_t>(remainingStreamingBytes, length);
  593|      0|                    dataHandler(user, std::string_view(data, emittable), emittable == remainingStreamingBytes);
  594|      0|                    remainingStreamingBytes -= emittable;
  595|       |
  596|      0|                    data += emittable;
  597|      0|                    length -= emittable;
  598|      0|                    consumedTotal += emittable;
  599|      0|                }
  600|    749|            } else {
  601|       |                /* If we came here without a body; emit an empty data chunk to signal no data */
  602|    749|                dataHandler(user, {}, true);
  603|    749|            }
  604|       |
  605|       |            /* Consume minimally should break as easrly as possible */
  606|  2.21k|            if (CONSUME_MINIMALLY) {
  ------------------
  |  Branch (606:17): [Folded - Ignored]
  ------------------
  607|  2.21k|                break;
  608|  2.21k|            }
  609|  2.21k|        }
  610|       |        /* Whenever we return FULLPTR, the interpretation of "consumed" should be the HttpError enum. */
  611|  36.5k|        if (err) {
  ------------------
  |  Branch (611:13): [True: 3.74k, False: 32.8k]
  ------------------
  612|  3.74k|            return {err, FULLPTR};
  613|  3.74k|        }
  614|  32.8k|        return {consumedTotal, user};
  615|  36.5k|    }
_ZN3uWS10HttpParser10getHeadersEPcS1_PNS_11HttpRequest6HeaderEPvRj:
  356|  98.5k|    static unsigned int getHeaders(char *postPaddedBuffer, char *end, struct HttpRequest::Header *headers, void *reserved, unsigned int &err) {
  357|  98.5k|        char *preliminaryKey, *preliminaryValue, *start = postPaddedBuffer;
  358|       |
  359|  98.5k|        #ifdef UWS_WITH_PROXY
  360|       |            /* ProxyParser is passed as reserved parameter */
  361|  98.5k|            ProxyParser *pp = (ProxyParser *) reserved;
  362|       |
  363|       |            /* Parse PROXY protocol */
  364|  98.5k|            auto [done, offset] = pp->parse({postPaddedBuffer, (size_t) (end - postPaddedBuffer)});
  365|  98.5k|            if (!done) {
  ------------------
  |  Branch (365:17): [True: 3.23k, False: 95.3k]
  ------------------
  366|       |                /* We do not reset the ProxyParser (on filure) since it is tied to this
  367|       |                * connection, which is really only supposed to ever get one PROXY frame
  368|       |                * anyways. We do however allow multiple PROXY frames to be sent (overwrites former). */
  369|  3.23k|                return 0;
  370|  95.3k|            } else {
  371|       |                /* We have consumed this data so skip it */
  372|  95.3k|                postPaddedBuffer += offset;
  373|  95.3k|            }
  374|       |        #else
  375|       |            /* This one is unused */
  376|       |            (void) reserved;
  377|       |            (void) end;
  378|       |        #endif
  379|       |
  380|       |        /* It is critical for fallback buffering logic that we only return with success
  381|       |         * if we managed to parse a complete HTTP request (minus data). Returning success
  382|       |         * for PROXY means we can end up succeeding, yet leaving bytes in the fallback buffer
  383|       |         * which is then removed, and our counters to flip due to overflow and we end up with a crash */
  384|       |
  385|       |        /* The request line is different from the field names / field values */
  386|  95.3k|        if ((char *) 2 > (postPaddedBuffer = consumeRequestLine(postPaddedBuffer, end, headers[0]))) {
  ------------------
  |  Branch (386:13): [True: 74.9k, False: 20.4k]
  ------------------
  387|       |            /* Error - invalid request line */
  388|       |            /* Assuming it is 505 HTTP Version Not Supported */
  389|  74.9k|            err = postPaddedBuffer ? HTTP_ERROR_505_HTTP_VERSION_NOT_SUPPORTED : 0;
  ------------------
  |  Branch (389:19): [True: 46.7k, False: 28.2k]
  ------------------
  390|  74.9k|            return 0;
  391|  74.9k|        }
  392|  20.4k|        headers++;
  393|       |
  394|  65.1k|        for (unsigned int i = 1; i < UWS_HTTP_MAX_HEADERS_COUNT - 1; i++) {
  ------------------
  |  |   53|  65.1k|#define UWS_HTTP_MAX_HEADERS_COUNT 100
  ------------------
  |  Branch (394:34): [True: 64.9k, False: 194]
  ------------------
  395|       |            /* Lower case and consume the field name */
  396|  64.9k|            preliminaryKey = postPaddedBuffer;
  397|  64.9k|            postPaddedBuffer = (char *) consumeFieldName(postPaddedBuffer);
  398|  64.9k|            headers->key = std::string_view(preliminaryKey, (size_t) (postPaddedBuffer - preliminaryKey));
  399|       |
  400|       |            /* We should not accept whitespace between key and colon, so colon must foloow immediately */
  401|  64.9k|            if (postPaddedBuffer[0] != ':') {
  ------------------
  |  Branch (401:17): [True: 820, False: 64.1k]
  ------------------
  402|       |                /* If we stand at the end, we are fragmented */
  403|    820|                if (postPaddedBuffer == end) {
  ------------------
  |  Branch (403:21): [True: 571, False: 249]
  ------------------
  404|    571|                    return 0;
  405|    571|                }
  406|       |                /* Error: invalid chars in field name */
  407|    249|                err = HTTP_ERROR_400_BAD_REQUEST;
  408|    249|                return 0;
  409|    820|            }
  410|  64.1k|            postPaddedBuffer++;
  411|       |
  412|  64.1k|            preliminaryValue = postPaddedBuffer;
  413|       |            /* The goal of this call is to find next "\r\n", or any invalid field value chars, fast */
  414|  65.4k|            while (true) {
  ------------------
  |  Branch (414:20): [Folded - Ignored]
  ------------------
  415|  65.4k|                postPaddedBuffer = (char *) tryConsumeFieldValue(postPaddedBuffer);
  416|       |                /* If this is not CR then we caught some stinky invalid char on the way */
  417|  65.4k|                if (postPaddedBuffer[0] != '\r') {
  ------------------
  |  Branch (417:21): [True: 1.62k, False: 63.8k]
  ------------------
  418|       |                    /* If TAB then keep searching */
  419|  1.62k|                    if (postPaddedBuffer[0] == '\t') {
  ------------------
  |  Branch (419:25): [True: 1.36k, False: 264]
  ------------------
  420|  1.36k|                        postPaddedBuffer++;
  421|  1.36k|                        continue;
  422|  1.36k|                    }
  423|       |                    /* Error - invalid chars in field value */
  424|    264|                    err = HTTP_ERROR_400_BAD_REQUEST;
  425|    264|                    return 0;
  426|  1.62k|                }
  427|  63.8k|                break;
  428|  65.4k|            }
  429|       |            /* We fence end[0] with \r, followed by end[1] being something that is "not \n", to signify "not found".
  430|       |                * This way we can have this one single check to see if we found \r\n WITHIN our allowed search space. */
  431|  63.8k|            if (postPaddedBuffer[1] == '\n') {
  ------------------
  |  Branch (431:17): [True: 62.6k, False: 1.19k]
  ------------------
  432|       |                /* Store this header, it is valid */
  433|  62.6k|                headers->value = std::string_view(preliminaryValue, (size_t) (postPaddedBuffer - preliminaryValue));
  434|  62.6k|                postPaddedBuffer += 2;
  435|       |
  436|       |                /* Trim trailing whitespace (SP, HTAB) */
  437|  82.5k|                while (headers->value.length() && headers->value.back() < 33) {
  ------------------
  |  Branch (437:24): [True: 37.4k, False: 45.0k]
  |  Branch (437:51): [True: 19.8k, False: 17.6k]
  ------------------
  438|  19.8k|                    headers->value.remove_suffix(1);
  439|  19.8k|                }
  440|       |
  441|       |                /* Trim initial whitespace (SP, HTAB) */
  442|  98.8k|                while (headers->value.length() && headers->value.front() < 33) {
  ------------------
  |  Branch (442:24): [True: 53.7k, False: 45.0k]
  |  Branch (442:51): [True: 36.1k, False: 17.6k]
  ------------------
  443|  36.1k|                    headers->value.remove_prefix(1);
  444|  36.1k|                }
  445|       |                
  446|  62.6k|                headers++;
  447|       |
  448|       |                /* We definitely have at least one header (or request line), so check if we are done */
  449|  62.6k|                if (*postPaddedBuffer == '\r') {
  ------------------
  |  Branch (449:21): [True: 17.9k, False: 44.7k]
  ------------------
  450|  17.9k|                    if (postPaddedBuffer[1] == '\n') {
  ------------------
  |  Branch (450:25): [True: 17.2k, False: 712]
  ------------------
  451|       |                        /* This cann take the very last header space */
  452|  17.2k|                        headers->key = std::string_view(nullptr, 0);
  453|  17.2k|                        return (unsigned int) ((postPaddedBuffer + 2) - start);
  454|  17.2k|                    } else {
  455|       |                        /* \r\n\r plus non-\n letter is malformed request, or simply out of search space */
  456|    712|                        if (postPaddedBuffer + 1 < end) {
  ------------------
  |  Branch (456:29): [True: 202, False: 510]
  ------------------
  457|    202|                            err = HTTP_ERROR_400_BAD_REQUEST;
  458|    202|                        }
  459|    712|                        return 0;
  460|    712|                    }
  461|  17.9k|                }
  462|  62.6k|            } else {
  463|       |                /* We are either out of search space or this is a malformed request */
  464|  1.19k|                return 0;
  465|  1.19k|            }
  466|  63.8k|        }
  467|       |        /* We ran out of header space, too large request */
  468|    194|        err = HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE;
  469|    194|        return 0;
  470|  20.4k|    }
_ZN3uWS10HttpParser18consumeRequestLineEPcS1_RNS_11HttpRequest6HeaderE:
  293|  95.3k|    static inline char *consumeRequestLine(char *data, char *end, HttpRequest::Header &header) {
  294|       |        /* Scan until single SP, assume next is / (origin request) */
  295|  95.3k|        char *start = data;
  296|       |        /* This catches the post padded CR and fails */
  297|  95.6M|        while (data[0] > 32) data++;
  ------------------
  |  Branch (297:16): [True: 95.5M, False: 95.3k]
  ------------------
  298|  95.3k|        if (&data[1] == end) [[unlikely]] {
  ------------------
  |  Branch (298:13): [True: 196, False: 95.1k]
  ------------------
  299|    196|            return nullptr;
  300|    196|        }
  301|  95.1k|        if (data[0] == 32 && data[1] == '/') [[likely]] {
  ------------------
  |  Branch (301:13): [True: 23.0k, False: 72.1k]
  |  Branch (301:30): [True: 22.6k, False: 404]
  ------------------
  302|  22.6k|            header.key = {start, (size_t) (data - start)};
  303|  22.6k|            data++;
  304|       |            /* Scan for less than 33 (catches post padded CR and fails) */
  305|  22.6k|            start = data;
  306|   369k|            for (; true; data += 8) {
  ------------------
  |  Branch (306:20): [Folded - Ignored]
  ------------------
  307|   369k|                uint64_t word;
  308|   369k|                memcpy(&word, data, sizeof(uint64_t));
  309|   369k|                if (hasLess(word, 33)) {
  ------------------
  |  Branch (309:21): [True: 22.6k, False: 346k]
  ------------------
  310|  93.3k|                    while (*(unsigned char *)data > 32) data++;
  ------------------
  |  Branch (310:28): [True: 70.7k, False: 22.6k]
  ------------------
  311|       |                    /* Now we stand on space */
  312|  22.6k|                    header.value = {start, (size_t) (data - start)};
  313|       |                    /* Check that the following is http 1.1 */
  314|  22.6k|                    if (data + 11 >= end) {
  ------------------
  |  Branch (314:25): [True: 727, False: 21.8k]
  ------------------
  315|       |                        /* Whatever we have must be part of the version string */
  316|    727|                        if (memcmp(" HTTP/1.1\r\n", data, std::min<unsigned int>(11, (unsigned int) (end - data))) == 0) {
  ------------------
  |  Branch (316:29): [True: 382, False: 345]
  ------------------
  317|    382|                            return nullptr;
  318|    382|                        }
  319|    345|                        return (char *) 0x1;
  320|    727|                    }
  321|  21.8k|                    if (memcmp(" HTTP/1.1\r\n", data, 11) == 0) {
  ------------------
  |  Branch (321:25): [True: 20.4k, False: 1.47k]
  ------------------
  322|  20.4k|                        return data + 11;
  323|  20.4k|                    }
  324|       |                    /* If we stand at the post padded CR, we have fragmented input so try again later */
  325|  1.47k|                    if (data[0] == '\r') {
  ------------------
  |  Branch (325:25): [True: 520, False: 954]
  ------------------
  326|    520|                        return nullptr;
  327|    520|                    }
  328|       |                    /* This is an error */
  329|    954|                    return (char *) 0x1;
  330|  1.47k|                }
  331|   369k|            }
  332|  22.6k|        }
  333|       |        /* If we stand at the post padded CR, we have fragmented input so try again later */
  334|  72.5k|        if (data[0] == '\r') {
  ------------------
  |  Branch (334:13): [True: 27.1k, False: 45.4k]
  ------------------
  335|  27.1k|            return nullptr;
  336|  27.1k|        }
  337|  45.4k|        return (char *) 0x1;
  338|  72.5k|    }
_ZN3uWS10HttpParser7hasLessEmm:
  220|  1.23M|    static inline uint64_t hasLess(uint64_t x, uint64_t n) {
  221|  1.23M|        return (((x)-~0ULL/255*(n))&~(x)&~0ULL/255*128);
  222|  1.23M|    }
_ZN3uWS10HttpParser16consumeFieldNameEPc:
  264|  64.9k|    static inline void *consumeFieldName(char *p) {
  265|       |        /* Best case fast path (particularly useful with clang) */
  266|  85.0k|        while (true) {
  ------------------
  |  Branch (266:16): [Folded - Ignored]
  ------------------
  267|   102k|            while ((*p >= 65) & (*p <= 90)) [[likely]] {
  ------------------
  |  Branch (267:20): [True: 17.3k, False: 85.0k]
  ------------------
  268|  17.3k|                *p |= 32;
  269|  17.3k|                p++;
  270|  17.3k|            }
  271|   342k|            while (((*p >= 97) & (*p <= 122))) [[likely]] {
  ------------------
  |  Branch (271:20): [True: 257k, False: 85.0k]
  ------------------
  272|   257k|                p++;
  273|   257k|            }
  274|  85.0k|            if (*p == ':') {
  ------------------
  |  Branch (274:17): [True: 56.6k, False: 28.4k]
  ------------------
  275|  56.6k|                return (void *)p;
  276|  56.6k|            }
  277|  28.4k|            if (*p == '-') {
  ------------------
  |  Branch (277:17): [True: 9.26k, False: 19.1k]
  ------------------
  278|  9.26k|                p++;
  279|  19.1k|            } else if (!((*p >= 65) & (*p <= 90))) {
  ------------------
  |  Branch (279:24): [True: 8.29k, False: 10.8k]
  ------------------
  280|       |                /* Exit fast path parsing */
  281|  8.29k|                break;
  282|  8.29k|            }
  283|  28.4k|        }
  284|       |
  285|       |        /* Generic */
  286|   105k|        while (isFieldNameByteFastLowercased(*(unsigned char *)p)) {
  ------------------
  |  Branch (286:16): [True: 96.8k, False: 8.29k]
  ------------------
  287|  96.8k|            p++;
  288|  96.8k|        }
  289|  8.29k|        return (void *)p;
  290|  64.9k|    }
_ZN3uWS10HttpParser29isFieldNameByteFastLowercasedERh:
  249|   105k|    static inline bool isFieldNameByteFastLowercased(unsigned char &in) {
  250|       |        /* Most common is lowercase alpha and hyphen */
  251|   105k|        if (((in >= 97) & (in <= 122)) | (in == '-')) [[likely]] {
  ------------------
  |  Branch (251:13): [True: 47.3k, False: 57.7k]
  ------------------
  252|  47.3k|            return true;
  253|       |        /* Second is upper case alpha */
  254|  57.7k|        } else if ((in >= 65) & (in <= 90)) [[unlikely]] {
  ------------------
  |  Branch (254:20): [True: 18.4k, False: 39.3k]
  ------------------
  255|  18.4k|            in |= 32;
  256|  18.4k|            return true;
  257|       |        /* These are rarely used but still valid */
  258|  39.3k|        } else if (isUnlikelyFieldNameByte(in)) [[unlikely]] {
  ------------------
  |  Branch (258:20): [True: 31.0k, False: 8.29k]
  ------------------
  259|  31.0k|            return true;
  260|  31.0k|        }
  261|  8.29k|        return false;
  262|   105k|    }
_ZN3uWS10HttpParser23isUnlikelyFieldNameByteEh:
  243|  39.3k|    {
  244|       |        /* Digits and 14 of the 15 non-alphanum characters (lacking hyphen) */
  245|  39.3k|        return ((c == '~') | (c == '|') | (c == '`') | (c == '_') | (c == '^') | (c == '.') | (c == '+')
  ------------------
  |  Branch (245:16): [True: 22.0k, False: 17.2k]
  ------------------
  246|  39.3k|            | (c == '*') | (c == '!')) || ((c >= 48) & (c <= 57)) || ((c <= 39) & (c >= 35));
  ------------------
  |  Branch (246:43): [True: 5.64k, False: 11.6k]
  |  Branch (246:70): [True: 3.36k, False: 8.29k]
  ------------------
  247|  39.3k|    }
_ZN3uWS10HttpParser20tryConsumeFieldValueEPc:
  344|  65.4k|    static inline void *tryConsumeFieldValue(char *p) {
  345|   866k|        for (; true; p += 8) {
  ------------------
  |  Branch (345:16): [Folded - Ignored]
  ------------------
  346|   866k|            uint64_t word;
  347|   866k|            memcpy(&word, p, sizeof(uint64_t));
  348|   866k|            if (hasLess(word, 32)) {
  ------------------
  |  Branch (348:17): [True: 65.4k, False: 801k]
  ------------------
  349|   119k|                while (*(unsigned char *)p > 31) p++;
  ------------------
  |  Branch (349:24): [True: 53.8k, False: 65.4k]
  ------------------
  350|  65.4k|                return (void *)p;
  351|  65.4k|            }
  352|   866k|        }
  353|  65.4k|    }
_ZN3uWS11HttpRequest9getHeaderENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
  115|  62.4k|    std::string_view getHeader(std::string_view lowerCasedHeader) {
  116|  62.4k|        if (bf.mightHave(lowerCasedHeader)) {
  ------------------
  |  Branch (116:13): [True: 22.7k, False: 39.6k]
  ------------------
  117|  48.2k|            for (Header *h = headers; (++h)->key.length(); ) {
  ------------------
  |  Branch (117:39): [True: 46.5k, False: 1.79k]
  ------------------
  118|  46.5k|                if (h->key.length() == lowerCasedHeader.length() && !strncmp(h->key.data(), lowerCasedHeader.data(), lowerCasedHeader.length())) {
  ------------------
  |  Branch (118:21): [True: 22.9k, False: 23.5k]
  |  Branch (118:69): [True: 20.9k, False: 1.95k]
  ------------------
  119|  20.9k|                    return h->value;
  120|  20.9k|                }
  121|  46.5k|            }
  122|  22.7k|        }
  123|  41.4k|        return std::string_view(nullptr, 0);
  124|  62.4k|    }
_ZN3uWS10HttpParser17toUnsignedIntegerENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
  203|  1.74k|    static uint64_t toUnsignedInteger(std::string_view str) {
  204|       |        /* We assume at least 64-bit integer giving us safely 999999999999999999 (18 number of 9s) */
  205|  1.74k|        if (str.length() > 18) {
  ------------------
  |  Branch (205:13): [True: 34, False: 1.70k]
  ------------------
  206|     34|            return UINT64_MAX;
  207|     34|        }
  208|       |
  209|  1.70k|        uint64_t unsignedIntegerValue = 0;
  210|  6.45k|        for (char c : str) {
  ------------------
  |  Branch (210:21): [True: 6.45k, False: 1.64k]
  ------------------
  211|       |            /* As long as the letter is 0-9 we cannot overflow. */
  212|  6.45k|            if (c < '0' || c > '9') {
  ------------------
  |  Branch (212:17): [True: 51, False: 6.40k]
  |  Branch (212:28): [True: 14, False: 6.39k]
  ------------------
  213|     65|                return UINT64_MAX;
  214|     65|            }
  215|  6.39k|            unsignedIntegerValue = unsignedIntegerValue * 10ull + ((unsigned int) c - (unsigned int) '0');
  216|  6.39k|        }
  217|  1.64k|        return unsignedIntegerValue;
  218|  1.70k|    }
_ZN3uWS10HttpParser25fenceAndConsumePostPaddedILi0EEENSt3__14pairIjPvEEPcjS4_S4_PNS_11HttpRequestERN5ofats13any_invocableIFS4_S4_S8_EEERNSA_IFS4_S4_NS2_17basic_string_viewIcNS2_11char_traitsIcEEEEbEEE:
  477|  74.2k|    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) {
  478|       |
  479|       |        /* How much data we CONSUMED (to throw away) */
  480|  74.2k|        unsigned int consumedTotal = 0;
  481|  74.2k|        unsigned int err = 0;
  482|       |
  483|       |        /* Fence two bytes past end of our buffer (buffer has post padded margins).
  484|       |         * This is to always catch scan for \r but not for \r\n. */
  485|  74.2k|        data[length] = '\r';
  486|  74.2k|        data[length + 1] = 'a'; /* Anything that is not \n, to trigger "invalid request" */
  487|       |
  488|  85.8k|        for (unsigned int consumed; length && (consumed = getHeaders(data, data + length, req->headers, reserved, err)); ) {
  ------------------
  |  Branch (488:37): [True: 60.3k, False: 25.5k]
  |  Branch (488:47): [True: 13.2k, False: 47.0k]
  ------------------
  489|  13.2k|            data += consumed;
  490|  13.2k|            length -= consumed;
  491|  13.2k|            consumedTotal += consumed;
  492|       |
  493|       |            /* Even if we could parse it, check for length here as well */
  494|  13.2k|            if (consumed > MAX_FALLBACK_SIZE) {
  ------------------
  |  Branch (494:17): [True: 20, False: 13.2k]
  ------------------
  495|     20|                return {HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE, FULLPTR};
  496|     20|            }
  497|       |
  498|       |            /* Store HTTP version (ancient 1.0 or 1.1) */
  499|  13.2k|            req->ancientHttp = false;
  500|       |
  501|       |            /* Add all headers to bloom filter */
  502|  13.2k|            req->bf.reset();
  503|  40.0k|            for (HttpRequest::Header *h = req->headers; (++h)->key.length(); ) {
  ------------------
  |  Branch (503:57): [True: 26.9k, False: 13.0k]
  ------------------
  504|  26.9k|                if (req->bf.mightHave(h->key)) [[unlikely]] {
  ------------------
  |  Branch (504:21): [True: 3.73k, False: 23.2k]
  ------------------
  505|       |                    /* Host header is not allowed twice */
  506|  3.73k|                    if (h->key == "host" && req->getHeader("host").data()) {
  ------------------
  |  Branch (506:25): [True: 194, False: 3.54k]
  |  Branch (506:25): [True: 194, False: 3.54k]
  |  Branch (506:45): [True: 194, False: 0]
  ------------------
  507|    194|                        return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  508|    194|                    }
  509|  3.73k|                }
  510|  26.7k|                req->bf.add(h->key);
  511|  26.7k|            }
  512|       |            
  513|       |            /* Break if no host header (but we can have empty string which is different from nullptr) */
  514|  13.0k|            if (!req->getHeader("host").data()) {
  ------------------
  |  Branch (514:17): [True: 355, False: 12.7k]
  ------------------
  515|    355|                return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  516|    355|            }
  517|       |
  518|       |            /* RFC 9112 6.3
  519|       |            * If a message is received with both a Transfer-Encoding and a Content-Length header field,
  520|       |            * the Transfer-Encoding overrides the Content-Length. Such a message might indicate an attempt
  521|       |            * to perform request smuggling (Section 11.2) or response splitting (Section 11.1) and
  522|       |            * ought to be handled as an error. */
  523|  12.7k|            std::string_view transferEncodingString = req->getHeader("transfer-encoding");
  524|  12.7k|            std::string_view contentLengthString = req->getHeader("content-length");
  525|  12.7k|            if (transferEncodingString.length() && contentLengthString.length()) {
  ------------------
  |  Branch (525:17): [True: 2.12k, False: 10.5k]
  |  Branch (525:52): [True: 208, False: 1.91k]
  ------------------
  526|       |                /* Returning fullptr is the same as calling the errorHandler */
  527|       |                /* We could be smart and set an error in the context along with this, to indicate what 
  528|       |                 * http error response we might want to return */
  529|    208|                return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  530|    208|            }
  531|       |
  532|       |            /* Parse query */
  533|  12.5k|            const char *querySeparatorPtr = (const char *) memchr(req->headers->value.data(), '?', req->headers->value.length());
  534|  12.5k|            req->querySeparator = (unsigned int) ((querySeparatorPtr ? querySeparatorPtr : req->headers->value.data() + req->headers->value.length()) - req->headers->value.data());
  ------------------
  |  Branch (534:52): [True: 5.24k, False: 7.26k]
  ------------------
  535|       |
  536|       |            /* If returned socket is not what we put in we need
  537|       |             * to break here as we either have upgraded to
  538|       |             * WebSockets or otherwise closed the socket. */
  539|  12.5k|            void *returnedUser = requestHandler(user, req);
  540|  12.5k|            if (returnedUser != user) {
  ------------------
  |  Branch (540:17): [True: 762, False: 11.7k]
  ------------------
  541|       |                /* We are upgraded to WebSocket or otherwise broken */
  542|    762|                return {consumedTotal, returnedUser};
  543|    762|            }
  544|       |
  545|       |            /* The rules at play here according to RFC 9112 for requests are essentially:
  546|       |             * If both content-length and transfer-encoding then invalid message; must break.
  547|       |             * If has transfer-encoding then must be chunked regardless of value.
  548|       |             * If content-length then fixed length even if 0.
  549|       |             * If none of the above then fixed length is 0. */
  550|       |
  551|       |            /* RFC 9112 6.3
  552|       |             * If a message is received with both a Transfer-Encoding and a Content-Length header field,
  553|       |             * the Transfer-Encoding overrides the Content-Length. */
  554|  11.7k|            if (transferEncodingString.length()) {
  ------------------
  |  Branch (554:17): [True: 1.90k, False: 9.84k]
  ------------------
  555|       |
  556|       |                /* If a proxy sent us the transfer-encoding header that 100% means it must be chunked or else the proxy is
  557|       |                 * not RFC 9112 compliant. Therefore it is always better to assume this is the case, since that entirely eliminates 
  558|       |                 * all forms of transfer-encoding obfuscation tricks. We just rely on the header. */
  559|       |
  560|       |                /* RFC 9112 6.3
  561|       |                 * If a Transfer-Encoding header field is present in a request and the chunked transfer coding is not the
  562|       |                 * final encoding, the message body length cannot be determined reliably; the server MUST respond with the
  563|       |                 * 400 (Bad Request) status code and then close the connection. */
  564|       |
  565|       |                /* In this case we fail later by having the wrong interpretation (assuming chunked).
  566|       |                 * This could be made stricter but makes no difference either way, unless forwarding the identical message as a proxy. */
  567|       |
  568|  1.90k|                remainingStreamingBytes = STATE_IS_CHUNKED;
  569|       |                /* If consume minimally, we do not want to consume anything but we want to mark this as being chunked */
  570|  1.90k|                if (!CONSUME_MINIMALLY) {
  ------------------
  |  Branch (570:21): [Folded - Ignored]
  ------------------
  571|       |                    /* Go ahead and parse it (todo: better heuristics for emitting FIN to the app level) */
  572|  1.90k|                    std::string_view dataToConsume(data, length);
  573|  2.34k|                    for (auto chunk : uWS::ChunkIterator(&dataToConsume, &remainingStreamingBytes)) {
  ------------------
  |  Branch (573:37): [True: 2.34k, False: 1.90k]
  ------------------
  574|  2.34k|                        dataHandler(user, chunk, chunk.length() == 0);
  575|  2.34k|                    }
  576|  1.90k|                    if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) {
  ------------------
  |  Branch (576:25): [True: 21, False: 1.87k]
  ------------------
  577|     21|                        return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  578|     21|                    }
  579|  1.87k|                    unsigned int consumed = (length - (unsigned int) dataToConsume.length());
  580|  1.87k|                    data = (char *) dataToConsume.data();
  581|  1.87k|                    length = (unsigned int) dataToConsume.length();
  582|  1.87k|                    consumedTotal += consumed;
  583|  1.87k|                }
  584|  9.84k|            } else if (contentLengthString.length()) {
  ------------------
  |  Branch (584:24): [True: 976, False: 8.86k]
  ------------------
  585|    976|                remainingStreamingBytes = toUnsignedInteger(contentLengthString);
  586|    976|                if (remainingStreamingBytes == UINT64_MAX) {
  ------------------
  |  Branch (586:21): [True: 57, False: 919]
  ------------------
  587|       |                    /* Parser error */
  588|     57|                    return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  589|     57|                }
  590|       |
  591|    919|                if (!CONSUME_MINIMALLY) {
  ------------------
  |  Branch (591:21): [Folded - Ignored]
  ------------------
  592|    919|                    unsigned int emittable = (unsigned int) std::min<uint64_t>(remainingStreamingBytes, length);
  593|    919|                    dataHandler(user, std::string_view(data, emittable), emittable == remainingStreamingBytes);
  594|    919|                    remainingStreamingBytes -= emittable;
  595|       |
  596|    919|                    data += emittable;
  597|    919|                    length -= emittable;
  598|    919|                    consumedTotal += emittable;
  599|    919|                }
  600|  8.86k|            } else {
  601|       |                /* If we came here without a body; emit an empty data chunk to signal no data */
  602|  8.86k|                dataHandler(user, {}, true);
  603|  8.86k|            }
  604|       |
  605|       |            /* Consume minimally should break as easrly as possible */
  606|  11.6k|            if (CONSUME_MINIMALLY) {
  ------------------
  |  Branch (606:17): [Folded - Ignored]
  ------------------
  607|      0|                break;
  608|      0|            }
  609|  11.6k|        }
  610|       |        /* Whenever we return FULLPTR, the interpretation of "consumed" should be the HttpError enum. */
  611|  72.5k|        if (err) {
  ------------------
  |  Branch (611:13): [True: 43.8k, False: 28.7k]
  ------------------
  612|  43.8k|            return {err, FULLPTR};
  613|  43.8k|        }
  614|  28.7k|        return {consumedTotal, user};
  615|  72.5k|    }
_ZN3uWS11HttpRequest6getUrlEv:
  126|  29.5k|    std::string_view getUrl() {
  127|  29.5k|        return std::string_view(headers->value.data(), querySeparator);
  128|  29.5k|    }
_ZN3uWS11HttpRequest9getMethodEv:
  139|  29.5k|    std::string_view getMethod() {
  140|       |        /* Compatibility hack: lower case method (todo: remove when major version bumps) */
  141|   137k|        for (unsigned int i = 0; i < headers->key.length(); i++) {
  ------------------
  |  Branch (141:34): [True: 107k, False: 29.5k]
  ------------------
  142|   107k|            ((char *) headers->key.data())[i] |= 32;
  143|   107k|        }
  144|       |
  145|  29.5k|        return std::string_view(headers->key.data(), headers->key.length());
  146|  29.5k|    }
_ZN3uWS11HttpRequest8getQueryEv:
  149|  14.7k|    std::string_view getQuery() {
  150|  14.7k|        if (querySeparator < headers->value.length()) {
  ------------------
  |  Branch (150:13): [True: 5.51k, False: 9.26k]
  ------------------
  151|       |            /* Strip the initial ? */
  152|  5.51k|            return std::string_view(headers->value.data() + querySeparator + 1, headers->value.length() - querySeparator - 1);
  153|  9.26k|        } else {
  154|  9.26k|            return std::string_view(nullptr, 0);
  155|  9.26k|        }
  156|  14.7k|    }
_ZN3uWS11HttpRequest8getQueryENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
  159|  29.5k|    std::string_view getQuery(std::string_view key) {
  160|       |        /* Raw querystring including initial '?' sign */
  161|  29.5k|        std::string_view queryString = std::string_view(headers->value.data() + querySeparator, headers->value.length() - querySeparator);
  162|       |
  163|  29.5k|        return getDecodedQueryValue(key, queryString);
  164|  29.5k|    }
_ZN3uWS11HttpRequest5beginEv:
  102|  13.9k|    HeaderIterator begin() {
  103|  13.9k|        return {headers + 1};
  104|  13.9k|    }
_ZN3uWS11HttpRequest3endEv:
  106|  13.9k|    HeaderIterator end() {
  107|  13.9k|        return {nullptr};
  108|  13.9k|    }
_ZNK3uWS11HttpRequest14HeaderIteratorneERKS1_:
   84|  42.3k|        bool operator!=(const HeaderIterator &other) const {
   85|       |            /* Comparison with end is a special case */
   86|  42.3k|            if (ptr != other.ptr) {
  ------------------
  |  Branch (86:17): [True: 42.3k, False: 0]
  ------------------
   87|  42.3k|                return other.ptr || ptr->key.length();
  ------------------
  |  Branch (87:24): [True: 0, False: 42.3k]
  |  Branch (87:37): [True: 28.3k, False: 13.9k]
  ------------------
   88|  42.3k|            }
   89|      0|            return false;
   90|  42.3k|        }
_ZNK3uWS11HttpRequest14HeaderIteratordeEv:
   97|  28.3k|        std::pair<std::string_view, std::string_view> operator*() const {
   98|  28.3k|            return {ptr->key, ptr->value};
   99|  28.3k|        }
_ZN3uWS11HttpRequest14HeaderIteratorppEv:
   92|  28.3k|        HeaderIterator &operator++() {
   93|  28.3k|            ptr++;
   94|  28.3k|            return *this;
   95|  28.3k|        }

_ZN3uWS10HttpRouterIN10StaticData10RouterDataEEC2Ev:
  243|      2|    HttpRouter() {
  244|       |        /* Always have ANY route */
  245|      2|        getNode(&root, std::string(ANY_METHOD_TOKEN.data(), ANY_METHOD_TOKEN.length()), false);
  246|      2|    }
_ZN3uWS10HttpRouterIN10StaticData10RouterDataEE4NodeC2ENSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEE:
   63|     22|        Node(std::string name) : name(name) {}
_ZN3uWS10HttpRouterIN10StaticData10RouterDataEE7getNodeEPNS3_4NodeENSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEb:
   81|     24|    Node *getNode(Node *parent, std::string child, bool isHighPriority) {
   82|     24|        for (std::unique_ptr<Node> &node : parent->children) {
  ------------------
  |  Branch (82:42): [True: 16, False: 20]
  ------------------
   83|     16|            if (node->name == child && node->isHighPriority == isHighPriority) {
  ------------------
  |  Branch (83:17): [True: 4, False: 12]
  |  Branch (83:40): [True: 4, False: 0]
  ------------------
   84|      4|                return node.get();
   85|      4|            }
   86|     16|        }
   87|       |
   88|       |        /* Insert sorted, but keep order if parent is root (we sort methods by priority elsewhere) */
   89|     20|        std::unique_ptr<Node> newNode(new Node(child));
   90|     20|        newNode->isHighPriority = isHighPriority;
   91|     20|        return parent->children.emplace(std::upper_bound(parent->children.begin(), parent->children.end(), newNode, [parent, this](auto &a, auto &b) {
   92|       |
   93|     20|            if (a->isHighPriority != b->isHighPriority) {
   94|     20|                return a->isHighPriority;
   95|     20|            }
   96|       |
   97|     20|            return b->name.length() && (parent != &root) && (lexicalOrder(b->name) < lexicalOrder(a->name));
   98|     20|        }), std::move(newNode))->get();
   99|     24|    }
_ZZN3uWS10HttpRouterIN10StaticData10RouterDataEE7getNodeEPNS3_4NodeENSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEbENKUlRT_RT0_E_clIKNS6_10unique_ptrIS4_NS6_14default_deleteIS4_EEEESM_EEDaSE_SG_:
   91|     10|        return parent->children.emplace(std::upper_bound(parent->children.begin(), parent->children.end(), newNode, [parent, this](auto &a, auto &b) {
   92|       |
   93|     10|            if (a->isHighPriority != b->isHighPriority) {
  ------------------
  |  Branch (93:17): [True: 0, False: 10]
  ------------------
   94|      0|                return a->isHighPriority;
   95|      0|            }
   96|       |
   97|     10|            return b->name.length() && (parent != &root) && (lexicalOrder(b->name) < lexicalOrder(a->name));
  ------------------
  |  Branch (97:20): [True: 10, False: 0]
  |  Branch (97:40): [True: 6, False: 4]
  |  Branch (97:61): [True: 4, False: 2]
  ------------------
   98|     10|        }), std::move(newNode))->get();
_ZN3uWS10HttpRouterIN10StaticData10RouterDataEE12lexicalOrderERNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEE:
   67|     12|    int lexicalOrder(std::string &name) {
   68|     12|        if (!name.length()) {
  ------------------
  |  Branch (68:13): [True: 0, False: 12]
  ------------------
   69|      0|            return 2;
   70|      0|        }
   71|     12|        if (name[0] == ':') {
  ------------------
  |  Branch (71:13): [True: 4, False: 8]
  ------------------
   72|      4|            return 1;
   73|      4|        }
   74|      8|        if (name[0] == '*') {
  ------------------
  |  Branch (74:13): [True: 4, False: 4]
  ------------------
   75|      4|            return 0;
   76|      4|        }
   77|      4|        return 2;
   78|      8|    }
_ZN3uWS10HttpRouterIN10StaticData10RouterDataEE3addENSt3__16vectorINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEESB_ON5ofats13any_invocableIFbPS3_EEEj:
  282|      8|    void add(std::vector<std::string> methods, std::string pattern, MoveOnlyFunction<bool(HttpRouter *)> &&handler, uint32_t priority = MEDIUM_PRIORITY) {
  283|       |        /* First remove existing handler */
  284|      8|        remove(methods[0], pattern, priority);
  285|       |        
  286|      8|        for (std::string method : methods) {
  ------------------
  |  Branch (286:33): [True: 8, False: 8]
  ------------------
  287|       |            /* Lookup method */
  288|      8|            Node *node = getNode(&root, method, false);
  289|       |            /* Iterate over all segments */
  290|      8|            setUrl(pattern);
  291|     22|            for (int i = 0; !getUrlSegment(i).second; i++) {
  ------------------
  |  Branch (291:29): [True: 14, False: 8]
  ------------------
  292|     14|                std::string strippedSegment(getUrlSegment(i).first);
  293|     14|                if (strippedSegment.length() && strippedSegment[0] == ':') {
  ------------------
  |  Branch (293:21): [True: 14, False: 0]
  |  Branch (293:49): [True: 8, False: 6]
  ------------------
  294|       |                    /* Parameter routes must be named only : */
  295|      8|                    strippedSegment = ":";
  296|      8|                }
  297|     14|                node = getNode(node, strippedSegment, priority == HIGH_PRIORITY);
  298|     14|            }
  299|       |            /* Insert handler in order sorted by priority (most significant 1 byte) */
  300|      8|            node->handlers.insert(std::upper_bound(node->handlers.begin(), node->handlers.end(), (uint32_t) (priority | handlers.size())), (uint32_t) (priority | handlers.size()));
  301|      8|        }
  302|       |
  303|       |        /* Alloate this handler */
  304|      8|        handlers.emplace_back(std::move(handler));
  305|       |
  306|       |        /* ANY method must be last, GET must be first */
  307|      8|        std::sort(root.children.begin(), root.children.end(), [](const auto &a, const auto &b) {
  308|      8|            if (a->name == "GET" && b->name != "GET") {
  309|      8|                return true;
  310|      8|            } else if (b->name == "GET" && a->name != "GET") {
  311|      8|                return false;
  312|      8|            } else if (a->name == ANY_METHOD_TOKEN && b->name != ANY_METHOD_TOKEN) {
  313|      8|                return false;
  314|      8|            } else if (b->name == ANY_METHOD_TOKEN && a->name != ANY_METHOD_TOKEN) {
  315|      8|                return true;
  316|      8|            } else {
  317|      8|                return a->name < b->name;
  318|      8|            }
  319|      8|        });
  320|      8|    }
_ZN3uWS10HttpRouterIN10StaticData10RouterDataEE6removeENSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESA_j:
  362|      8|    bool remove(std::string method, std::string pattern, uint32_t priority) {
  363|      8|        uint32_t handler = findHandler(method, pattern, priority);
  364|      8|        if (handler == UINT32_MAX) {
  ------------------
  |  Branch (364:13): [True: 8, False: 0]
  ------------------
  365|       |            /* Not found or already removed, do nothing */
  366|      8|            return false;
  367|      8|        }
  368|       |
  369|       |        /* Cull the entire tree */
  370|       |        /* For all nodes in depth first tree traveral;
  371|       |         * if node contains handler - remove the handler -
  372|       |         * if node holds no handlers after removal, remove the node and return */
  373|      0|        cullNode(nullptr, &root, handler);
  374|       |
  375|       |        /* Now remove the actual handler */
  376|      0|        handlers.erase(handlers.begin() + (handler & HANDLER_MASK));
  377|       |
  378|      0|        return true;
  379|      8|    }
_ZN3uWS10HttpRouterIN10StaticData10RouterDataEE11findHandlerENSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESA_j:
  210|      8|    uint32_t findHandler(std::string method, std::string pattern, uint32_t priority) {
  211|     10|        for (std::unique_ptr<Node> &node : root.children) {
  ------------------
  |  Branch (211:42): [True: 10, False: 4]
  ------------------
  212|     10|            if (method == node->name) {
  ------------------
  |  Branch (212:17): [True: 4, False: 6]
  ------------------
  213|      4|                setUrl(pattern);
  214|      4|                Node *n = node.get();
  215|      4|                for (int i = 0; !getUrlSegment(i).second; i++) {
  ------------------
  |  Branch (215:33): [True: 4, False: 0]
  ------------------
  216|       |                    /* Go to next segment or quit */
  217|      4|                    std::string segment = std::string(getUrlSegment(i).first);
  218|      4|                    Node *next = nullptr;
  219|      6|                    for (std::unique_ptr<Node> &child : n->children) {
  ------------------
  |  Branch (219:55): [True: 6, False: 4]
  ------------------
  220|      6|                        if (((segment.length() && child->name.length() && segment[0] == ':' && child->name[0] == ':') || child->name == segment) && child->isHighPriority == (priority == HIGH_PRIORITY)) {
  ------------------
  |  Branch (220:31): [True: 6, False: 0]
  |  Branch (220:51): [True: 6, False: 0]
  |  Branch (220:75): [True: 0, False: 6]
  |  Branch (220:96): [True: 0, False: 0]
  |  Branch (220:122): [True: 0, False: 6]
  |  Branch (220:149): [True: 0, False: 0]
  ------------------
  221|      0|                            next = child.get();
  222|      0|                            break;
  223|      0|                        }
  224|      6|                    }
  225|      4|                    if (!next) {
  ------------------
  |  Branch (225:25): [True: 4, False: 0]
  ------------------
  226|      4|                        return UINT32_MAX;
  227|      4|                    }
  228|      0|                    n = next;
  229|      0|                }
  230|       |                /* Seek for a priority match in the found node */
  231|      0|                for (unsigned int i = 0; i < n->handlers.size(); i++) {
  ------------------
  |  Branch (231:42): [True: 0, False: 0]
  ------------------
  232|      0|                    if ((n->handlers[i] & ~HANDLER_MASK) == priority) {
  ------------------
  |  Branch (232:25): [True: 0, False: 0]
  ------------------
  233|      0|                        return n->handlers[i];
  234|      0|                    }
  235|      0|                }
  236|      0|                return UINT32_MAX;
  237|      0|            }
  238|     10|        }
  239|      4|        return UINT32_MAX;
  240|      8|    }
_ZN3uWS10HttpRouterIN10StaticData10RouterDataEE6setUrlENSt3__117basic_string_viewIcNS4_11char_traitsIcEEEE:
  124|  14.7k|    inline void setUrl(std::string_view url) {
  125|       |
  126|       |        /* Todo: URL may also start with "http://domain/" or "*", not only "/" */
  127|       |
  128|       |        /* We expect to stand on a slash */
  129|  14.7k|        currentUrl = url;
  130|  14.7k|        urlSegmentTop = -1;
  131|  14.7k|    }
_ZN3uWS10HttpRouterIN10StaticData10RouterDataEE13getUrlSegmentEi:
  134|  34.1k|    inline std::pair<std::string_view, bool> getUrlSegment(int urlSegment) {
  135|  34.1k|        if (urlSegment > urlSegmentTop) {
  ------------------
  |  Branch (135:13): [True: 33.5k, False: 575]
  ------------------
  136|       |            /* Signal as STOP when we have no more URL or stack space */
  137|  33.5k|            if (!currentUrl.length() || urlSegment > int(MAX_URL_SEGMENTS - 1)) {
  ------------------
  |  Branch (137:17): [True: 12.9k, False: 20.6k]
  |  Branch (137:41): [True: 0, False: 20.6k]
  ------------------
  138|  12.9k|                return {{}, true};
  139|  12.9k|            }
  140|       |
  141|       |            /* We always stand on a slash here, so step over it */
  142|  20.6k|            currentUrl.remove_prefix(1);
  143|       |
  144|  20.6k|            auto segmentLength = currentUrl.find('/');
  145|  20.6k|            if (segmentLength == std::string::npos) {
  ------------------
  |  Branch (145:17): [True: 14.6k, False: 6.02k]
  ------------------
  146|  14.6k|                segmentLength = currentUrl.length();
  147|       |
  148|       |                /* Push to url segment vector */
  149|  14.6k|                urlSegmentVector[urlSegment] = currentUrl.substr(0, segmentLength);
  150|  14.6k|                urlSegmentTop++;
  151|       |
  152|       |                /* Update currentUrl */
  153|  14.6k|                currentUrl = currentUrl.substr(segmentLength);
  154|  14.6k|            } else {
  155|       |                /* Push to url segment vector */
  156|  6.02k|                urlSegmentVector[urlSegment] = currentUrl.substr(0, segmentLength);
  157|  6.02k|                urlSegmentTop++;
  158|       |
  159|       |                /* Update currentUrl */
  160|  6.02k|                currentUrl = currentUrl.substr(segmentLength);
  161|  6.02k|            }
  162|  20.6k|        }
  163|       |        /* In any case we return it */
  164|  21.2k|        return {urlSegmentVector[urlSegment], false};
  165|  34.1k|    }
_ZZN3uWS10HttpRouterIN10StaticData10RouterDataEE3addENSt3__16vectorINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEESB_ON5ofats13any_invocableIFbPS3_EEEjENKUlRKT_RKT0_E_clINS4_10unique_ptrINS3_4NodeENS4_14default_deleteIST_EEEESW_EEDaSM_SP_:
  307|     16|        std::sort(root.children.begin(), root.children.end(), [](const auto &a, const auto &b) {
  308|     16|            if (a->name == "GET" && b->name != "GET") {
  ------------------
  |  Branch (308:17): [True: 0, False: 16]
  |  Branch (308:37): [True: 0, False: 0]
  ------------------
  309|      0|                return true;
  310|     16|            } else if (b->name == "GET" && a->name != "GET") {
  ------------------
  |  Branch (310:24): [True: 0, False: 16]
  |  Branch (310:44): [True: 0, False: 0]
  ------------------
  311|      0|                return false;
  312|     16|            } else if (a->name == ANY_METHOD_TOKEN && b->name != ANY_METHOD_TOKEN) {
  ------------------
  |  Branch (312:24): [True: 6, False: 10]
  |  Branch (312:55): [True: 6, False: 0]
  ------------------
  313|      6|                return false;
  314|     10|            } else if (b->name == ANY_METHOD_TOKEN && a->name != ANY_METHOD_TOKEN) {
  ------------------
  |  Branch (314:24): [True: 4, False: 6]
  |  Branch (314:55): [True: 4, False: 0]
  ------------------
  315|      4|                return true;
  316|      6|            } else {
  317|      6|                return a->name < b->name;
  318|      6|            }
  319|     16|        });
_ZN3uWS10HttpRouterIN10StaticData10RouterDataEE13getParametersEv:
  248|  14.1k|    std::pair<int, std::string_view *> getParameters() {
  249|  14.1k|        return {routeParameters.paramsTop, routeParameters.params};
  250|  14.1k|    }
_ZN3uWS10HttpRouterIN10StaticData10RouterDataEE11getUserDataEv:
  252|  14.7k|    USERDATA &getUserData() {
  253|  14.7k|        return userData;
  254|  14.7k|    }
_ZN3uWS10HttpRouterIN10StaticData10RouterDataEE5routeENSt3__117basic_string_viewIcNS4_11char_traitsIcEEEES8_:
  257|  14.7k|    bool route(std::string_view method, std::string_view url) {
  258|       |        /* Reset url parsing cache */
  259|  14.7k|        setUrl(url);
  260|  14.7k|        routeParameters.reset();
  261|       |
  262|       |        /* Begin by finding the method node */
  263|  17.2k|        for (auto &p : root.children) {
  ------------------
  |  Branch (263:22): [True: 17.2k, False: 655]
  ------------------
  264|  17.2k|            if (p->name == method) {
  ------------------
  |  Branch (264:17): [True: 14.1k, False: 3.10k]
  ------------------
  265|       |                /* Then route the url */
  266|  14.1k|                if (executeHandlers(p.get(), 0, userData)) {
  ------------------
  |  Branch (266:21): [True: 13.9k, False: 123]
  ------------------
  267|  13.9k|                    return true;
  268|  13.9k|                } else {
  269|    123|                    break;
  270|    123|                }
  271|  14.1k|            }
  272|  17.2k|        }
  273|       |
  274|       |        /* Always test any route last (this check should not be necessary if we always have at least one handler) */
  275|    778|        if (root.children.empty()) [[unlikely]] {
  ------------------
  |  Branch (275:13): [True: 0, False: 778]
  ------------------
  276|      0|            return false;
  277|      0|        }
  278|    778|        return executeHandlers(root.children.back().get(), 0, userData);
  279|    778|    }
_ZN3uWS10HttpRouterIN10StaticData10RouterDataEE15RouteParameters5resetEv:
  108|  14.7k|        void reset() {
  109|  14.7k|            paramsTop = -1;
  110|  14.7k|        }
_ZN3uWS10HttpRouterIN10StaticData10RouterDataEE15executeHandlersEPNS3_4NodeEiRS2_:
  168|  34.1k|    bool executeHandlers(Node *parent, int urlSegment, USERDATA &userData) {
  169|       |
  170|  34.1k|        auto [segment, isStop] = getUrlSegment(urlSegment);
  171|       |
  172|       |        /* If we are on STOP, return where we may stand */
  173|  34.1k|        if (isStop) {
  ------------------
  |  Branch (173:13): [True: 12.9k, False: 21.1k]
  ------------------
  174|       |            /* We have reached accross the entire URL with no stoppage, execute */
  175|  12.9k|            for (uint32_t handler : parent->handlers) {
  ------------------
  |  Branch (175:35): [True: 12.8k, False: 71]
  ------------------
  176|  12.8k|                if (handlers[handler & HANDLER_MASK](this)) {
  ------------------
  |  Branch (176:21): [True: 12.8k, False: 0]
  ------------------
  177|  12.8k|                    return true;
  178|  12.8k|                }
  179|  12.8k|            }
  180|       |            /* We reached the end, so go back */
  181|     71|            return false;
  182|  12.9k|        }
  183|       |
  184|  23.7k|        for (auto &p : parent->children) {
  ------------------
  |  Branch (184:22): [True: 23.7k, False: 1.37k]
  ------------------
  185|  23.7k|            if (p->name.length() && p->name[0] == '*') {
  ------------------
  |  Branch (185:17): [True: 23.7k, False: 0]
  |  Branch (185:37): [True: 1.24k, False: 22.4k]
  ------------------
  186|       |                /* Wildcard match (can be seen as a shortcut) */
  187|  1.24k|                for (uint32_t handler : p->handlers) {
  ------------------
  |  Branch (187:39): [True: 1.24k, False: 117]
  ------------------
  188|  1.24k|                    if (handlers[handler & HANDLER_MASK](this)) {
  ------------------
  |  Branch (188:25): [True: 1.13k, False: 117]
  ------------------
  189|  1.13k|                        return true;
  190|  1.13k|                    }
  191|  1.24k|                }
  192|  22.4k|            } else if (p->name.length() && p->name[0] == ':' && segment.length()) {
  ------------------
  |  Branch (192:24): [True: 22.4k, False: 0]
  |  Branch (192:44): [True: 9.47k, False: 12.9k]
  |  Branch (192:65): [True: 9.43k, False: 42]
  ------------------
  193|       |                /* Parameter match */
  194|  9.43k|                routeParameters.push(segment);
  195|  9.43k|                if (executeHandlers(p.get(), urlSegment + 1, userData)) {
  ------------------
  |  Branch (195:21): [True: 9.33k, False: 106]
  ------------------
  196|  9.33k|                    return true;
  197|  9.33k|                }
  198|    106|                routeParameters.pop();
  199|  13.0k|            } else if (p->name == segment) {
  ------------------
  |  Branch (199:24): [True: 9.76k, False: 3.25k]
  ------------------
  200|       |                /* Static match */
  201|  9.76k|                if (executeHandlers(p.get(), urlSegment + 1, userData)) {
  ------------------
  |  Branch (201:21): [True: 9.33k, False: 434]
  ------------------
  202|  9.33k|                    return true;
  203|  9.33k|                }
  204|  9.76k|            }
  205|  23.7k|        }
  206|  1.37k|        return false;
  207|  21.1k|    }
_ZN3uWS10HttpRouterIN10StaticData10RouterDataEE15RouteParameters4pushENSt3__117basic_string_viewIcNS5_11char_traitsIcEEEE:
  112|  9.43k|        void push(std::string_view param) {
  113|       |            /* We check these bounds indirectly via the urlSegments limit */
  114|  9.43k|            params[++paramsTop] = param;
  115|  9.43k|        }
_ZN3uWS10HttpRouterIN10StaticData10RouterDataEE15RouteParameters3popEv:
  117|    106|        void pop() {
  118|       |            /* Same here, we cannot pop outside */
  119|    106|            paramsTop--;
  120|    106|        }

_ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEEC2EOS8_:
  191|     14|  any_invocable_impl(any_invocable_impl&& rhs) noexcept {
  192|     14|    if (rhs.handle_) {
  ------------------
  |  Branch (192:9): [True: 14, False: 0]
  ------------------
  193|     14|      handle_ = rhs.handle_;
  194|     14|      handle_(action::move, &storage_, &rhs.storage_);
  195|     14|      call_ = rhs.call_;
  196|     14|      rhs.handle_ = nullptr;
  197|     14|    }
  198|     14|  }
_ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEED2Ev:
  209|     14|  ~any_invocable_impl() { destroy(); }
_ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE7destroyEv:
  242|     14|  void destroy() noexcept {
  243|     14|    if (handle_) {
  ------------------
  |  Branch (243:9): [True: 0, False: 14]
  ------------------
  244|      0|      handle_(action::destroy, &storage_, nullptr);
  245|      0|      handle_ = nullptr;
  246|      0|    }
  247|     14|  }
_ZN5ofats13any_invocableIFbPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEEC2IZNS3_C1EvEUlPT_E_vEEOSA_:
  306|      2|    any_invocable(F&& f) {                                                     \
  307|      2|      base_type::template create<std::decay_t<F>>(std::forward<F>(f));         \
  308|      2|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEEC2Ev:
  189|      8|  any_invocable_impl() noexcept = default;
_ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE6createIZNS4_C1EvEUlPT_E_JSC_EEEvDpOT0_:
  235|      2|  void create(Args&&... args) {
  236|      2|    using hdl = handler<F>;
  237|      2|    hdl::create(storage_, std::forward<Args>(args)...);
  238|      2|    handle_ = &hdl::handle;
  239|      2|    call_ = &hdl::call;
  240|      2|  }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E_E6createIJSC_EEEvRNS0_7storageEDpOT_:
  121|      8|    static void create(storage& s, Args&&... args) {
  122|      8|      new (static_cast<void*>(&s.buf_)) T(std::forward<Args>(args)...);
  123|      8|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE12handler_baseINS8_13small_handlerIZNS4_C1EvEUlPT_E_EEE6handleENS0_6actionEPNS0_7storageESI_:
  106|      6|    static void handle(action act, storage* current, storage* other = nullptr) {
  107|      6|      switch (act) {
  ------------------
  |  Branch (107:15): [True: 0, False: 6]
  ------------------
  108|      0|        case (action::destroy):
  ------------------
  |  Branch (108:9): [True: 0, False: 6]
  ------------------
  109|      0|          Derived::destroy(*current);
  110|      0|          break;
  111|      6|        case (action::move):
  ------------------
  |  Branch (111:9): [True: 6, False: 0]
  ------------------
  112|      6|          Derived::move(*current, *other);
  113|      6|          break;
  114|      6|      }
  115|      6|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E_E7destroyERNS0_7storageE:
  125|      6|    static void destroy(storage& s) noexcept {
  126|      6|      T& value = *static_cast<T*>(static_cast<void*>(&s.buf_));
  127|      6|      value.~T();
  128|      6|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E_E4moveERNS0_7storageESF_:
  130|      6|    static void move(storage& dst, storage& src) noexcept {
  131|      6|      create(dst, std::move(*static_cast<T*>(static_cast<void*>(&src.buf_))));
  132|      6|      destroy(src);
  133|      6|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E_E4callERNS0_7storageES7_:
  135|  3.53k|    static R call(storage& s, ArgTypes... args) {
  136|  3.53k|      return std::invoke(*static_cast<T*>(static_cast<void*>(&s.buf_)),
  137|  3.53k|                         std::forward<ArgTypes>(args)...);
  138|  3.53k|    }
_ZN5ofats13any_invocableIFbPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEEC2IZNS3_C1EvEUlPT_E0_vEEOSA_:
  306|      2|    any_invocable(F&& f) {                                                     \
  307|      2|      base_type::template create<std::decay_t<F>>(std::forward<F>(f));         \
  308|      2|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE6createIZNS4_C1EvEUlPT_E0_JSC_EEEvDpOT0_:
  235|      2|  void create(Args&&... args) {
  236|      2|    using hdl = handler<F>;
  237|      2|    hdl::create(storage_, std::forward<Args>(args)...);
  238|      2|    handle_ = &hdl::handle;
  239|      2|    call_ = &hdl::call;
  240|      2|  }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E0_E6createIJSC_EEEvRNS0_7storageEDpOT_:
  121|      6|    static void create(storage& s, Args&&... args) {
  122|      6|      new (static_cast<void*>(&s.buf_)) T(std::forward<Args>(args)...);
  123|      6|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE12handler_baseINS8_13small_handlerIZNS4_C1EvEUlPT_E0_EEE6handleENS0_6actionEPNS0_7storageESI_:
  106|      4|    static void handle(action act, storage* current, storage* other = nullptr) {
  107|      4|      switch (act) {
  ------------------
  |  Branch (107:15): [True: 0, False: 4]
  ------------------
  108|      0|        case (action::destroy):
  ------------------
  |  Branch (108:9): [True: 0, False: 4]
  ------------------
  109|      0|          Derived::destroy(*current);
  110|      0|          break;
  111|      4|        case (action::move):
  ------------------
  |  Branch (111:9): [True: 4, False: 0]
  ------------------
  112|      4|          Derived::move(*current, *other);
  113|      4|          break;
  114|      4|      }
  115|      4|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E0_E7destroyERNS0_7storageE:
  125|      4|    static void destroy(storage& s) noexcept {
  126|      4|      T& value = *static_cast<T*>(static_cast<void*>(&s.buf_));
  127|      4|      value.~T();
  128|      4|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E0_E4moveERNS0_7storageESF_:
  130|      4|    static void move(storage& dst, storage& src) noexcept {
  131|      4|      create(dst, std::move(*static_cast<T*>(static_cast<void*>(&src.buf_))));
  132|      4|      destroy(src);
  133|      4|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E0_E4callERNS0_7storageES7_:
  135|  1.13k|    static R call(storage& s, ArgTypes... args) {
  136|  1.13k|      return std::invoke(*static_cast<T*>(static_cast<void*>(&s.buf_)),
  137|  1.13k|                         std::forward<ArgTypes>(args)...);
  138|  1.13k|    }
_ZN5ofats13any_invocableIFbPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEEC2IZNS3_C1EvEUlPT_E1_vEEOSA_:
  306|      2|    any_invocable(F&& f) {                                                     \
  307|      2|      base_type::template create<std::decay_t<F>>(std::forward<F>(f));         \
  308|      2|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE6createIZNS4_C1EvEUlPT_E1_JSC_EEEvDpOT0_:
  235|      2|  void create(Args&&... args) {
  236|      2|    using hdl = handler<F>;
  237|      2|    hdl::create(storage_, std::forward<Args>(args)...);
  238|      2|    handle_ = &hdl::handle;
  239|      2|    call_ = &hdl::call;
  240|      2|  }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E1_E6createIJSC_EEEvRNS0_7storageEDpOT_:
  121|      4|    static void create(storage& s, Args&&... args) {
  122|      4|      new (static_cast<void*>(&s.buf_)) T(std::forward<Args>(args)...);
  123|      4|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE12handler_baseINS8_13small_handlerIZNS4_C1EvEUlPT_E1_EEE6handleENS0_6actionEPNS0_7storageESI_:
  106|      2|    static void handle(action act, storage* current, storage* other = nullptr) {
  107|      2|      switch (act) {
  ------------------
  |  Branch (107:15): [True: 0, False: 2]
  ------------------
  108|      0|        case (action::destroy):
  ------------------
  |  Branch (108:9): [True: 0, False: 2]
  ------------------
  109|      0|          Derived::destroy(*current);
  110|      0|          break;
  111|      2|        case (action::move):
  ------------------
  |  Branch (111:9): [True: 2, False: 0]
  ------------------
  112|      2|          Derived::move(*current, *other);
  113|      2|          break;
  114|      2|      }
  115|      2|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E1_E7destroyERNS0_7storageE:
  125|      2|    static void destroy(storage& s) noexcept {
  126|      2|      T& value = *static_cast<T*>(static_cast<void*>(&s.buf_));
  127|      2|      value.~T();
  128|      2|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E1_E4moveERNS0_7storageESF_:
  130|      2|    static void move(storage& dst, storage& src) noexcept {
  131|      2|      create(dst, std::move(*static_cast<T*>(static_cast<void*>(&src.buf_))));
  132|      2|      destroy(src);
  133|      2|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E1_E4callERNS0_7storageES7_:
  135|    117|    static R call(storage& s, ArgTypes... args) {
  136|    117|      return std::invoke(*static_cast<T*>(static_cast<void*>(&s.buf_)),
  137|    117|                         std::forward<ArgTypes>(args)...);
  138|    117|    }
_ZN5ofats13any_invocableIFbPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEEC2IZNS3_C1EvEUlPT_E2_vEEOSA_:
  306|      2|    any_invocable(F&& f) {                                                     \
  307|      2|      base_type::template create<std::decay_t<F>>(std::forward<F>(f));         \
  308|      2|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE6createIZNS4_C1EvEUlPT_E2_JSC_EEEvDpOT0_:
  235|      2|  void create(Args&&... args) {
  236|      2|    using hdl = handler<F>;
  237|      2|    hdl::create(storage_, std::forward<Args>(args)...);
  238|      2|    handle_ = &hdl::handle;
  239|      2|    call_ = &hdl::call;
  240|      2|  }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E2_E6createIJSC_EEEvRNS0_7storageEDpOT_:
  121|      4|    static void create(storage& s, Args&&... args) {
  122|      4|      new (static_cast<void*>(&s.buf_)) T(std::forward<Args>(args)...);
  123|      4|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE12handler_baseINS8_13small_handlerIZNS4_C1EvEUlPT_E2_EEE6handleENS0_6actionEPNS0_7storageESI_:
  106|      2|    static void handle(action act, storage* current, storage* other = nullptr) {
  107|      2|      switch (act) {
  ------------------
  |  Branch (107:15): [True: 0, False: 2]
  ------------------
  108|      0|        case (action::destroy):
  ------------------
  |  Branch (108:9): [True: 0, False: 2]
  ------------------
  109|      0|          Derived::destroy(*current);
  110|      0|          break;
  111|      2|        case (action::move):
  ------------------
  |  Branch (111:9): [True: 2, False: 0]
  ------------------
  112|      2|          Derived::move(*current, *other);
  113|      2|          break;
  114|      2|      }
  115|      2|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E2_E7destroyERNS0_7storageE:
  125|      2|    static void destroy(storage& s) noexcept {
  126|      2|      T& value = *static_cast<T*>(static_cast<void*>(&s.buf_));
  127|      2|      value.~T();
  128|      2|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E2_E4moveERNS0_7storageESF_:
  130|      2|    static void move(storage& dst, storage& src) noexcept {
  131|      2|      create(dst, std::move(*static_cast<T*>(static_cast<void*>(&src.buf_))));
  132|      2|      destroy(src);
  133|      2|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E2_E4callERNS0_7storageES7_:
  135|  9.33k|    static R call(storage& s, ArgTypes... args) {
  136|  9.33k|      return std::invoke(*static_cast<T*>(static_cast<void*>(&s.buf_)),
  137|  9.33k|                         std::forward<ArgTypes>(args)...);
  138|  9.33k|    }
_ZN5ofats13any_invocableIFPvS1_NSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEbEEclES1_S6_b:
  348|  39.4k|    R operator()(ArgTypes... args) cv ref noexcept(noex) {                     \
  349|  39.4k|      return base_type::call(std::forward<ArgTypes>(args)...);                 \
  350|  39.4k|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE4callES2_S7_b:
  249|  39.4k|  R call(ArgTypes... args) noexcept(is_noexcept) {
  250|  39.4k|    return call_(storage_, std::forward<ArgTypes>(args)...);
  251|  39.4k|  }
_ZN5ofats13any_invocableIFPvS1_PN3uWS11HttpRequestEEEclES1_S4_:
  348|  14.7k|    R operator()(ArgTypes... args) cv ref noexcept(noex) {                     \
  349|  14.7k|      return base_type::call(std::forward<ArgTypes>(args)...);                 \
  350|  14.7k|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_PN3uWS11HttpRequestEEE4callES2_S5_:
  249|  14.7k|  R call(ArgTypes... args) noexcept(is_noexcept) {
  250|  14.7k|    return call_(storage_, std::forward<ArgTypes>(args)...);
  251|  14.7k|  }
Http.cpp:_ZN5ofats13any_invocableIFPvS1_PN3uWS11HttpRequestEEEC2IZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmEUlS1_S4_E_vEEOT_:
  306|   111k|    any_invocable(F&& f) {                                                     \
  307|   111k|      base_type::template create<std::decay_t<F>>(std::forward<F>(f));         \
  308|   111k|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_PN3uWS11HttpRequestEEEC2Ev:
  189|   111k|  any_invocable_impl() noexcept = default;
Http.cpp:_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_PN3uWS11HttpRequestEEE6createIZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmEUlS2_S5_E_JSB_EEEvDpOT0_:
  235|   111k|  void create(Args&&... args) {
  236|   111k|    using hdl = handler<F>;
  237|   111k|    hdl::create(storage_, std::forward<Args>(args)...);
  238|   111k|    handle_ = &hdl::handle;
  239|   111k|    call_ = &hdl::call;
  240|   111k|  }
Http.cpp:_ZN5ofats10any_detail14handler_traitsIPvJS2_PN3uWS11HttpRequestEEE13small_handlerIZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmEUlS2_S5_E_E6createIJSB_EEEvRNS0_7storageEDpOT_:
  121|   111k|    static void create(storage& s, Args&&... args) {
  122|   111k|      new (static_cast<void*>(&s.buf_)) T(std::forward<Args>(args)...);
  123|   111k|    }
Http.cpp:_ZN5ofats10any_detail14handler_traitsIPvJS2_PN3uWS11HttpRequestEEE12handler_baseINS6_13small_handlerIZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmEUlS2_S5_E_EEE6handleENS0_6actionEPNS0_7storageESH_:
  106|   111k|    static void handle(action act, storage* current, storage* other = nullptr) {
  107|   111k|      switch (act) {
  ------------------
  |  Branch (107:15): [True: 0, False: 111k]
  ------------------
  108|   111k|        case (action::destroy):
  ------------------
  |  Branch (108:9): [True: 111k, False: 0]
  ------------------
  109|   111k|          Derived::destroy(*current);
  110|   111k|          break;
  111|      0|        case (action::move):
  ------------------
  |  Branch (111:9): [True: 0, False: 111k]
  ------------------
  112|      0|          Derived::move(*current, *other);
  113|      0|          break;
  114|   111k|      }
  115|   111k|    }
Http.cpp:_ZN5ofats10any_detail14handler_traitsIPvJS2_PN3uWS11HttpRequestEEE13small_handlerIZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmEUlS2_S5_E_E7destroyERNS0_7storageE:
  125|   111k|    static void destroy(storage& s) noexcept {
  126|   111k|      T& value = *static_cast<T*>(static_cast<void*>(&s.buf_));
  127|   111k|      value.~T();
  128|   111k|    }
Http.cpp:_ZN5ofats10any_detail14handler_traitsIPvJS2_PN3uWS11HttpRequestEEE13small_handlerIZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmEUlS2_S5_E_E4callERNS0_7storageES2_S5_:
  135|  14.7k|    static R call(storage& s, ArgTypes... args) {
  136|  14.7k|      return std::invoke(*static_cast<T*>(static_cast<void*>(&s.buf_)),
  137|  14.7k|                         std::forward<ArgTypes>(args)...);
  138|  14.7k|    }
_ZN5ofats13any_invocableIFbPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEEclES6_:
  348|  14.1k|    R operator()(ArgTypes... args) cv ref noexcept(noex) {                     \
  349|  14.1k|      return base_type::call(std::forward<ArgTypes>(args)...);                 \
  350|  14.1k|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE4callES7_:
  249|  14.1k|  R call(ArgTypes... args) noexcept(is_noexcept) {
  250|  14.1k|    return call_(storage_, std::forward<ArgTypes>(args)...);
  251|  14.1k|  }
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_PN3uWS11HttpRequestEEED2Ev:
  209|   111k|  ~any_invocable_impl() { destroy(); }
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_PN3uWS11HttpRequestEEE7destroyEv:
  242|   111k|  void destroy() noexcept {
  243|   111k|    if (handle_) {
  ------------------
  |  Branch (243:9): [True: 111k, False: 0]
  ------------------
  244|   111k|      handle_(action::destroy, &storage_, nullptr);
  245|   111k|      handle_ = nullptr;
  246|   111k|    }
  247|   111k|  }
Http.cpp:_ZN5ofats13any_invocableIFPvS1_NSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEbEEC2IZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmEUlS1_S6_bE_vEEOT_:
  306|   111k|    any_invocable(F&& f) {                                                     \
  307|   111k|      base_type::template create<std::decay_t<F>>(std::forward<F>(f));         \
  308|   111k|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEEC2Ev:
  189|   111k|  any_invocable_impl() noexcept = default;
Http.cpp:_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE6createIZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmEUlS2_S7_bE_JSD_EEEvDpOT0_:
  235|   111k|  void create(Args&&... args) {
  236|   111k|    using hdl = handler<F>;
  237|   111k|    hdl::create(storage_, std::forward<Args>(args)...);
  238|   111k|    handle_ = &hdl::handle;
  239|   111k|    call_ = &hdl::call;
  240|   111k|  }
Http.cpp:_ZN5ofats10any_detail14handler_traitsIPvJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE13small_handlerIZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmEUlS2_S7_bE_E6createIJSD_EEEvRNS0_7storageEDpOT_:
  121|   111k|    static void create(storage& s, Args&&... args) {
  122|   111k|      new (static_cast<void*>(&s.buf_)) T(std::forward<Args>(args)...);
  123|   111k|    }
Http.cpp:_ZN5ofats10any_detail14handler_traitsIPvJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE12handler_baseINS8_13small_handlerIZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmEUlS2_S7_bE_EEE6handleENS0_6actionEPNS0_7storageESJ_:
  106|   111k|    static void handle(action act, storage* current, storage* other = nullptr) {
  107|   111k|      switch (act) {
  ------------------
  |  Branch (107:15): [True: 0, False: 111k]
  ------------------
  108|   111k|        case (action::destroy):
  ------------------
  |  Branch (108:9): [True: 111k, False: 0]
  ------------------
  109|   111k|          Derived::destroy(*current);
  110|   111k|          break;
  111|      0|        case (action::move):
  ------------------
  |  Branch (111:9): [True: 0, False: 111k]
  ------------------
  112|      0|          Derived::move(*current, *other);
  113|      0|          break;
  114|   111k|      }
  115|   111k|    }
Http.cpp:_ZN5ofats10any_detail14handler_traitsIPvJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE13small_handlerIZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmEUlS2_S7_bE_E7destroyERNS0_7storageE:
  125|   111k|    static void destroy(storage& s) noexcept {
  126|   111k|      T& value = *static_cast<T*>(static_cast<void*>(&s.buf_));
  127|   111k|      value.~T();
  128|   111k|    }
Http.cpp:_ZN5ofats10any_detail14handler_traitsIPvJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE13small_handlerIZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmEUlS2_S7_bE_E4callERNS0_7storageES2_S7_b:
  135|  39.4k|    static R call(storage& s, ArgTypes... args) {
  136|  39.4k|      return std::invoke(*static_cast<T*>(static_cast<void*>(&s.buf_)),
  137|  39.4k|                         std::forward<ArgTypes>(args)...);
  138|  39.4k|    }
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEED2Ev:
  209|   111k|  ~any_invocable_impl() { destroy(); }
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE7destroyEv:
  242|   111k|  void destroy() noexcept {
  243|   111k|    if (handle_) {
  ------------------
  |  Branch (243:9): [True: 111k, False: 0]
  ------------------
  244|   111k|      handle_(action::destroy, &storage_, nullptr);
  245|   111k|      handle_ = nullptr;
  246|   111k|    }
  247|   111k|  }

_ZN3uWS11ProxyParser5parseENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
   95|  98.5k|    std::pair<bool, unsigned int> parse(std::string_view data) {
   96|       |
   97|       |        /* We require at least four bytes to determine protocol */
   98|  98.5k|        if (data.length() < 4) {
  ------------------
  |  Branch (98:13): [True: 1.03k, False: 97.5k]
  ------------------
   99|  1.03k|            return {false, 0};
  100|  1.03k|        }
  101|       |
  102|       |        /* HTTP can never start with "\r\n\r\n", but PROXY always does */
  103|  97.5k|        if (memcmp(data.data(), "\r\n\r\n", 4)) {
  ------------------
  |  Branch (103:13): [True: 94.4k, False: 3.09k]
  ------------------
  104|       |            /* This is HTTP, so be done */
  105|  94.4k|            return {true, 0};
  106|  94.4k|        }
  107|       |
  108|       |        /* We assume we are parsing PROXY V2 here */
  109|       |
  110|       |        /* We require 16 bytes here */
  111|  3.09k|        if (data.length() < 16) {
  ------------------
  |  Branch (111:13): [True: 447, False: 2.64k]
  ------------------
  112|    447|            return {false, 0};
  113|    447|        }
  114|       |
  115|       |        /* Header is 16 bytes */
  116|  2.64k|        struct proxy_hdr_v2 header;
  117|  2.64k|        memcpy(&header, data.data(), 16);
  118|       |
  119|  2.64k|        if (memcmp(header.sig, "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A", 12)) {
  ------------------
  |  Branch (119:13): [True: 405, False: 2.24k]
  ------------------
  120|       |            /* This is not PROXY protocol at all */
  121|    405|            return {false, 0};
  122|    405|        }
  123|       |
  124|       |        /* We only support version 2 */
  125|  2.24k|        if ((header.ver_cmd & 0xf0) >> 4 != 2) {
  ------------------
  |  Branch (125:13): [True: 211, False: 2.03k]
  ------------------
  126|    211|            return {false, 0};
  127|    211|        }
  128|       |
  129|       |        //printf("Version: %d\n", (header.ver_cmd & 0xf0) >> 4);
  130|       |        //printf("Command: %d\n", (header.ver_cmd & 0x0f));
  131|       |
  132|       |        /* We get length in network byte order (todo: share this function with the rest) */
  133|  2.03k|        uint16_t hostLength = _cond_byte_swap<uint16_t>(header.len);
  134|       |
  135|       |        /* We must have all the data available */
  136|  2.03k|        if (data.length() < 16u + hostLength) {
  ------------------
  |  Branch (136:13): [True: 242, False: 1.78k]
  ------------------
  137|    242|            return {false, 0};
  138|    242|        }
  139|       |
  140|       |        /* Payload cannot be more than sizeof proxy_addr */
  141|  1.78k|        if (sizeof(proxy_addr) < hostLength) {
  ------------------
  |  Branch (141:13): [True: 894, False: 894]
  ------------------
  142|    894|            return {false, 0};
  143|    894|        }
  144|       |
  145|       |        //printf("Family: %d\n", (header.fam & 0xf0) >> 4);
  146|       |        //printf("Transport: %d\n", (header.fam & 0x0f));
  147|       |
  148|       |        /* We have 0 family by default, and UNSPEC is 0 as well */
  149|    894|        family = header.fam;
  150|       |
  151|       |        /* Copy payload */
  152|    894|        memcpy(&addr, data.data() + 16, hostLength);
  153|       |
  154|       |        /* We consumed everything */
  155|    894|        return {true, 16 + hostLength};
  156|  1.78k|    }
_ZN3uWS15_cond_byte_swapItEET_S1_:
   52|  2.03k|T _cond_byte_swap(T value) {
   53|  2.03k|    uint32_t endian_test = 1;
   54|  2.03k|    if (*((char *)&endian_test)) {
  ------------------
  |  Branch (54:9): [True: 2.03k, False: 0]
  ------------------
   55|  2.03k|        union {
   56|  2.03k|            T i;
   57|  2.03k|            uint8_t b[sizeof(T)];
   58|  2.03k|        } src = { value }, dst;
   59|       |
   60|  6.09k|        for (unsigned int i = 0; i < sizeof(value); i++) {
  ------------------
  |  Branch (60:34): [True: 4.06k, False: 2.03k]
  ------------------
   61|  4.06k|            dst.b[i] = src.b[sizeof(value) - 1 - i];
   62|  4.06k|        }
   63|       |
   64|  2.03k|        return dst.i;
   65|  2.03k|    }
   66|      0|    return value;
   67|  2.03k|}
_ZN3uWS11ProxyParser16getSourceAddressEv:
   78|  14.7k|    std::string_view getSourceAddress() {
   79|       |
   80|       |        // UNSPEC family and protocol
   81|  14.7k|        if (family == 0) {
  ------------------
  |  Branch (81:13): [True: 11.0k, False: 3.69k]
  ------------------
   82|  11.0k|            return {};
   83|  11.0k|        }
   84|       |
   85|  3.69k|        if ((family & 0xf0) >> 4 == 1) {
  ------------------
  |  Branch (85:13): [True: 2.90k, False: 788]
  ------------------
   86|       |            /* Family 1 is INET4 */
   87|  2.90k|            return {(char *) &addr.ipv4_addr.src_addr, 4};
   88|  2.90k|        } else {
   89|       |            /* Family 2 is INET6 */
   90|    788|            return {(char *) &addr.ipv6_addr.src_addr, 16};
   91|    788|        }
   92|  3.69k|    }

Http.cpp:_ZN3uWSL20getDecodedQueryValueENSt3__117basic_string_viewIcNS0_11char_traitsIcEEEES4_:
   28|  29.5k|    static inline std::string_view getDecodedQueryValue(std::string_view key, std::string_view rawQuery) {
   29|       |
   30|       |        /* Can't have a value without a key */
   31|  29.5k|        if (!key.length()) {
  ------------------
  |  Branch (31:13): [True: 14.7k, False: 14.7k]
  ------------------
   32|  14.7k|            return {};
   33|  14.7k|        }
   34|       |
   35|       |        /* Start with the whole querystring including initial '?' */
   36|  14.7k|        std::string_view queryString = rawQuery;
   37|       |
   38|       |        /* List of key, value could be cached for repeated fetches similar to how headers are, todo! */
   39|  27.2k|        while (queryString.length()) {
  ------------------
  |  Branch (39:16): [True: 16.8k, False: 10.4k]
  ------------------
   40|       |            /* Find boundaries of this statement */
   41|  16.8k|            std::string_view statement = queryString.substr(1, queryString.find('&', 1) - 1);
   42|       |
   43|       |            /* Only bother if first char of key match (early exit) */
   44|  16.8k|            if (statement.length() && statement[0] == key[0]) {
  ------------------
  |  Branch (44:17): [True: 7.93k, False: 8.87k]
  |  Branch (44:39): [True: 5.48k, False: 2.44k]
  ------------------
   45|       |                /* Equal sign must be present and not in the end of statement */
   46|  5.48k|                auto equality = statement.find('=');
   47|  5.48k|                if (equality != std::string_view::npos) {
  ------------------
  |  Branch (47:21): [True: 5.00k, False: 479]
  ------------------
   48|       |
   49|  5.00k|                    std::string_view statementKey = statement.substr(0, equality);
   50|  5.00k|                    std::string_view statementValue = statement.substr(equality + 1);
   51|       |
   52|       |                    /* String comparison */
   53|  5.00k|                    if (key == statementKey) {
  ------------------
  |  Branch (53:25): [True: 3.82k, False: 1.18k]
  ------------------
   54|       |
   55|       |                        /* Decode value inplace, put null at end if before length of original */
   56|  3.82k|                        char *in = (char *) statementValue.data();
   57|       |
   58|       |                        /* Write offset */
   59|  3.82k|                        unsigned int out = 0;
   60|       |
   61|       |                        /* Walk over all chars until end or null char, decoding in place */
   62|   713k|                        for (unsigned int i = 0; i < statementValue.length() && in[i]; i++) {
  ------------------
  |  Branch (62:50): [True: 709k, False: 3.60k]
  |  Branch (62:81): [True: 709k, False: 0]
  ------------------
   63|       |                                /* Only bother with '%' */
   64|   709k|                                if (in[i] == '%') {
  ------------------
  |  Branch (64:37): [True: 52.9k, False: 656k]
  ------------------
   65|       |                                    /* Do we have enough data for two bytes hex? */
   66|  52.9k|                                    if (i + 2 >= statementValue.length()) {
  ------------------
  |  Branch (66:41): [True: 219, False: 52.7k]
  ------------------
   67|    219|                                        return {};
   68|    219|                                    }
   69|       |
   70|       |                                    /* Two bytes hex */
   71|  52.7k|                                    int hex1 = in[i + 1] - '0';
   72|  52.7k|                                    if (hex1 > 9) {
  ------------------
  |  Branch (72:41): [True: 2.47k, False: 50.2k]
  ------------------
   73|  2.47k|                                        hex1 &= 223;
   74|  2.47k|                                        hex1 -= 7;
   75|  2.47k|                                    }
   76|       |
   77|  52.7k|                                    int hex2 = in[i + 2] - '0';
   78|  52.7k|                                    if (hex2 > 9) {
  ------------------
  |  Branch (78:41): [True: 3.68k, False: 49.0k]
  ------------------
   79|  3.68k|                                        hex2 &= 223;
   80|  3.68k|                                        hex2 -= 7;
   81|  3.68k|                                    }
   82|       |
   83|  52.7k|                                    *((unsigned char *) &in[out]) = (unsigned char) (hex1 * 16 + hex2);
   84|  52.7k|                                    i += 2;
   85|   656k|                                } else {
   86|       |                                    /* Is this even a rule? */
   87|   656k|                                    if (in[i] == '+') {
  ------------------
  |  Branch (87:41): [True: 76.5k, False: 580k]
  ------------------
   88|  76.5k|                                        in[out] = ' ';
   89|   580k|                                    } else {
   90|   580k|                                        in[out] = in[i];
   91|   580k|                                    }
   92|   656k|                                }
   93|       |
   94|       |                                /* We always only write one char */
   95|   709k|                                out++;
   96|   709k|                        }
   97|       |
   98|       |                        /* If decoded string is shorter than original, put null char to stop next read */
   99|  3.60k|                        if (out < statementValue.length()) {
  ------------------
  |  Branch (99:29): [True: 1.75k, False: 1.85k]
  ------------------
  100|  1.75k|                            in[out] = 0;
  101|  1.75k|                        }
  102|       |
  103|  3.60k|                        return statementValue.substr(0, out);
  104|  3.82k|                    }
  105|  5.00k|                } else {
  106|       |                    /* This querystring is invalid, cannot parse it */
  107|    479|                    return {nullptr, 0};
  108|    479|                }
  109|  5.48k|            }
  110|       |
  111|  12.5k|            queryString.remove_prefix(statement.length() + 1);
  112|  12.5k|        }
  113|       |
  114|       |        /* Nothing found is given as nullptr, while empty string is given as some pointer to the given buffer */
  115|  10.4k|        return {nullptr, 0};
  116|  14.7k|    }

