_ZN3uWS11BloomFilter5resetEv:
   75|  13.0k|    void reset() {
   76|  13.0k|        filter.reset();
   77|  13.0k|    }
_ZN3uWS11BloomFilter3addENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
   64|  26.9k|    void add(std::string_view key) {
   65|  26.9k|        if (key.length() >= 2) {
  ------------------
  |  Branch (65:13): [True: 24.4k, False: 2.50k]
  ------------------
   66|  24.4k|            ScrambleArea s = getFeatures(key);
   67|  24.4k|            s.val = perfectHash(s.val);
   68|  24.4k|            filter[s.p[0]] = 1;
   69|  24.4k|            filter[s.p[1]] = 1;
   70|  24.4k|            filter[s.p[2]] = 1;
   71|  24.4k|            filter[s.p[3]] = 1;
   72|  24.4k|        }
   73|  26.9k|    }
_ZN3uWS11BloomFilter11getFeaturesENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
   41|  68.1k|    ScrambleArea getFeatures(std::string_view key) {
   42|  68.1k|        ScrambleArea s;
   43|  68.1k|        s.p[0] = reinterpret_cast<const unsigned char&>(key[0]);
   44|  68.1k|        s.p[1] = reinterpret_cast<const unsigned char&>(key[key.length() - 1]);
   45|  68.1k|        s.p[2] = reinterpret_cast<const unsigned char&>(key[key.length() - 2]);
   46|  68.1k|        s.p[3] = reinterpret_cast<const unsigned char&>(key[key.length() >> 1]);
   47|  68.1k|        return s;
   48|  68.1k|    }
_ZN3uWS11BloomFilter11perfectHashEj:
   32|  68.1k|    static inline uint32_t perfectHash(uint32_t features) {
   33|  68.1k|        return features *= 1843993368;
   34|  68.1k|    }
_ZN3uWS11BloomFilter9mightHaveENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
   51|  44.2k|    bool mightHave(std::string_view key) {
   52|  44.2k|        if (key.length() < 2) {
  ------------------
  |  Branch (52:13): [True: 582, False: 43.6k]
  ------------------
   53|    582|            return true;
   54|    582|        }
   55|       |    
   56|  43.6k|        ScrambleArea s = getFeatures(key);
   57|  43.6k|        s.val = perfectHash(s.val);
   58|  43.6k|        return filter[s.p[0]] &&
  ------------------
  |  Branch (58:16): [True: 17.9k, False: 25.7k]
  ------------------
   59|  43.6k|        filter[s.p[1]] &&
  ------------------
  |  Branch (59:9): [True: 17.3k, False: 510]
  ------------------
   60|  43.6k|        filter[s.p[2]] &&
  ------------------
  |  Branch (60:9): [True: 17.1k, False: 290]
  ------------------
   61|  43.6k|        filter[s.p[3]];
  ------------------
  |  Branch (61:9): [True: 16.8k, False: 275]
  ------------------
   62|  44.2k|    }

_ZN3uWS24isParsingChunkedEncodingEm:
   95|  16.2k|    inline bool isParsingChunkedEncoding(uint64_t state) {
   96|  16.2k|        return state & ~STATE_SIZE_MASK;
   97|  16.2k|    }
_ZN3uWS13ChunkIteratorC2EPNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPmb:
  201|  16.2k|        ChunkIterator(std::string_view *data, uint64_t *state, bool trailer = false) : data(data), state(state), trailer(trailer) {
  202|  16.2k|            chunk = uWS::getNextChunk(*data, *state, trailer);
  203|  16.2k|        }
Http.cpp:_ZN3uWSL12getNextChunkERNSt3__117basic_string_viewIcNS0_11char_traitsIcEEEERmb:
  104|  32.5k|    static std::optional<std::string_view> getNextChunk(std::string_view &data, uint64_t &state, bool trailer = false) {
  105|       |
  106|  37.2k|        while (data.length()) {
  ------------------
  |  Branch (106:16): [True: 22.7k, False: 14.4k]
  ------------------
  107|       |
  108|       |            // if in "drop trailer mode", just drop up to what we have as size
  109|  22.7k|            if (((state & STATE_IS_CHUNKED) == 0) && hasChunkSize(state) && chunkSize(state)) {
  ------------------
  |  Branch (109:17): [True: 1.93k, False: 20.8k]
  |  Branch (109:54): [True: 1.93k, False: 0]
  |  Branch (109:77): [True: 1.93k, False: 0]
  ------------------
  110|       |
  111|       |                //printf("Parsing trailer now\n");
  112|       |
  113|  3.65k|                while(data.length() && chunkSize(state)) {
  ------------------
  |  Branch (113:23): [True: 3.41k, False: 233]
  |  Branch (113:40): [True: 3.41k, False: 0]
  ------------------
  114|  3.41k|                    data.remove_prefix(1);
  115|  3.41k|                    decChunkSize(state, 1);
  116|       |
  117|  3.41k|                    if (chunkSize(state) == 0) {
  ------------------
  |  Branch (117:25): [True: 1.70k, False: 1.71k]
  ------------------
  118|       |
  119|       |                        /* This is an actual place where we need 0 as state */
  120|  1.70k|                        state = 0;
  121|       |
  122|       |                        /* The parser MUST stop consuming here */
  123|  1.70k|                        return std::nullopt;
  124|  1.70k|                    }
  125|  3.41k|                }
  126|    233|                continue;
  127|  1.93k|            }
  128|       |
  129|  20.8k|            if (!hasChunkSize(state)) {
  ------------------
  |  Branch (129:17): [True: 5.91k, False: 14.9k]
  ------------------
  130|  5.91k|                consumeHexNumber(data, state);
  131|  5.91k|                if (isParsingInvalidChunkedEncoding(state)) {
  ------------------
  |  Branch (131:21): [True: 66, False: 5.85k]
  ------------------
  132|     66|                    return std::nullopt;
  133|     66|                }
  134|  5.85k|                if (hasChunkSize(state) && chunkSize(state) == 2) {
  ------------------
  |  Branch (134:21): [True: 4.55k, False: 1.29k]
  |  Branch (134:44): [True: 1.77k, False: 2.78k]
  ------------------
  135|       |
  136|       |                    //printf("Setting state to trailer-parsing and emitting empty chunk\n");
  137|       |
  138|       |                    // set trailer state and increase size to 4
  139|  1.77k|                    if (trailer) {
  ------------------
  |  Branch (139:25): [True: 0, False: 1.77k]
  ------------------
  140|      0|                        state = 4 /*| STATE_IS_CHUNKED*/ | STATE_HAS_SIZE;
  141|  1.77k|                    } else {
  142|  1.77k|                        state = 2 /*| STATE_IS_CHUNKED*/ | STATE_HAS_SIZE;
  143|  1.77k|                    }
  144|       |
  145|  1.77k|                    return std::string_view(nullptr, 0);
  146|  1.77k|                }
  147|  4.08k|                continue;
  148|  5.85k|            }
  149|       |
  150|       |            // do we have data to emit all?
  151|  14.9k|            if (data.length() >= chunkSize(state)) {
  ------------------
  |  Branch (151:17): [True: 2.54k, False: 12.3k]
  ------------------
  152|       |                // emit all but 2 bytes then reset state to 0 and goto beginning
  153|       |                // not fin
  154|  2.54k|                std::string_view emitSoon;
  155|  2.54k|                bool shouldEmit = false;
  156|  2.54k|                if (chunkSize(state) > 2) {
  ------------------
  |  Branch (156:21): [True: 2.14k, False: 398]
  ------------------
  157|  2.14k|                    emitSoon = std::string_view(data.data(), chunkSize(state) - 2);
  158|  2.14k|                    shouldEmit = true;
  159|  2.14k|                }
  160|  2.54k|                data.remove_prefix(chunkSize(state));
  161|  2.54k|                state = STATE_IS_CHUNKED;
  162|  2.54k|                if (shouldEmit) {
  ------------------
  |  Branch (162:21): [True: 2.14k, False: 398]
  ------------------
  163|  2.14k|                    return emitSoon;
  164|  2.14k|                }
  165|    398|                continue;
  166|  12.3k|            } else {
  167|       |                /* We will consume all our input data */
  168|  12.3k|                std::string_view emitSoon;
  169|  12.3k|                if (chunkSize(state) > 2) {
  ------------------
  |  Branch (169:21): [True: 12.3k, False: 1]
  ------------------
  170|  12.3k|                    uint64_t maximalAppEmit = chunkSize(state) - 2;
  171|  12.3k|                    if (data.length() > maximalAppEmit) {
  ------------------
  |  Branch (171:25): [True: 331, False: 12.0k]
  ------------------
  172|    331|                        emitSoon = data.substr(0, maximalAppEmit);
  173|  12.0k|                    } else {
  174|       |                        //cb(data);
  175|  12.0k|                        emitSoon = data;
  176|  12.0k|                    }
  177|  12.3k|                }
  178|  12.3k|                decChunkSize(state, (unsigned int) data.length());
  179|  12.3k|                state |= STATE_IS_CHUNKED;
  180|       |                // new: decrease data by its size (bug)
  181|  12.3k|                data.remove_prefix(data.length()); // ny bug fix för getNextChunk
  182|  12.3k|                if (emitSoon.length()) {
  ------------------
  |  Branch (182:21): [True: 12.3k, False: 1]
  ------------------
  183|  12.3k|                    return emitSoon;
  184|  12.3k|                } else {
  185|      1|                    return std::nullopt;
  186|      1|                }
  187|  12.3k|            }
  188|  14.9k|        }
  189|       |
  190|  14.4k|        return std::nullopt;
  191|  32.5k|    }
_ZN3uWS12hasChunkSizeEm:
   90|  28.6k|    inline bool hasChunkSize(uint64_t state) {
   91|  28.6k|        return state & STATE_HAS_SIZE;
   92|  28.6k|    }
_ZN3uWS9chunkSizeEm:
   38|   127k|    inline uint64_t chunkSize(uint64_t state) {
   39|   127k|        return state & STATE_SIZE_MASK;
   40|   127k|    }
_ZN3uWS12decChunkSizeERmj:
   81|  15.7k|    inline void decChunkSize(uint64_t &state, unsigned int by) {
   82|       |
   83|       |        //unsigned int bits = state & STATE_IS_CHUNKED;
   84|       |
   85|  15.7k|        state = (state & ~STATE_SIZE_MASK) | (chunkSize(state) - by);
   86|       |
   87|       |        //state |= bits;
   88|  15.7k|    }
_ZN3uWS16consumeHexNumberERNSt3__117basic_string_viewIcNS0_11char_traitsIcEEEERm:
   43|  5.91k|    inline void consumeHexNumber(std::string_view &data, uint64_t &state) {
   44|       |        /* Consume everything higher than 32 */
   45|  57.7k|        while (data.length() && data.data()[0] > 32) {
  ------------------
  |  Branch (45:16): [True: 57.0k, False: 699]
  |  Branch (45:33): [True: 51.8k, False: 5.15k]
  ------------------
   46|       |
   47|  51.8k|            unsigned char digit = (unsigned char)data.data()[0];
   48|  51.8k|            if (digit >= 'a') {
  ------------------
  |  Branch (48:17): [True: 1.59k, False: 50.2k]
  ------------------
   49|  1.59k|                digit = (unsigned char) (digit - ('a' - ':'));
   50|  50.2k|            } else if (digit >= 'A') {
  ------------------
  |  Branch (50:24): [True: 1.56k, False: 48.7k]
  ------------------
   51|  1.56k|                digit = (unsigned char) (digit - ('A' - ':'));
   52|  1.56k|            }
   53|       |
   54|  51.8k|            unsigned int number = ((unsigned int) digit - (unsigned int) '0');
   55|       |
   56|  51.8k|            if (number > 16 || (chunkSize(state) & STATE_SIZE_OVERFLOW)) {
  ------------------
  |  Branch (56:17): [True: 61, False: 51.8k]
  |  Branch (56:32): [True: 5, False: 51.8k]
  ------------------
   57|     66|                state = STATE_IS_ERROR;
   58|     66|                return;
   59|     66|            }
   60|       |
   61|       |            // extract state bits
   62|  51.8k|            uint64_t bits = /*state &*/ STATE_IS_CHUNKED;
   63|       |
   64|  51.8k|            state = (state & STATE_SIZE_MASK) * 16ull + number;
   65|       |
   66|  51.8k|            state |= bits;
   67|  51.8k|            data.remove_prefix(1);
   68|  51.8k|        }
   69|       |        /* Consume everything not /n */
   70|  62.4k|        while (data.length() && data.data()[0] != '\n') {
  ------------------
  |  Branch (70:16): [True: 61.1k, False: 1.29k]
  |  Branch (70:33): [True: 56.6k, False: 4.55k]
  ------------------
   71|  56.6k|            data.remove_prefix(1);
   72|  56.6k|        }
   73|       |        /* Now we stand on \n so consume it and enable size */
   74|  5.85k|        if (data.length()) {
  ------------------
  |  Branch (74:13): [True: 4.55k, False: 1.29k]
  ------------------
   75|  4.55k|            state += 2; // include the two last /r/n
   76|  4.55k|            state |= STATE_HAS_SIZE | STATE_IS_CHUNKED;
   77|  4.55k|            data.remove_prefix(1);
   78|  4.55k|        }
   79|  5.85k|    }
_ZN3uWS13ChunkIterator5beginEv:
  209|  16.2k|        ChunkIterator begin() {
  210|  16.2k|            return *this;
  211|  16.2k|        }
_ZN3uWS13ChunkIterator3endEv:
  213|  16.2k|        ChunkIterator end() {
  214|  16.2k|            return ChunkIterator();
  215|  16.2k|        }
_ZN3uWS13ChunkIteratorC2Ev:
  205|  16.2k|        ChunkIterator() {
  206|       |
  207|  16.2k|        }
_ZNK3uWS13ChunkIteratorneERKS0_:
  224|  32.5k|        bool operator!=(const ChunkIterator &other) const {
  225|  32.5k|            return other.chunk.has_value() != chunk.has_value();
  226|  32.5k|        }
_ZN3uWS13ChunkIteratordeEv:
  217|  16.2k|        std::string_view operator*() {
  218|  16.2k|            if (!chunk.has_value()) {
  ------------------
  |  Branch (218:17): [True: 0, False: 16.2k]
  ------------------
  219|      0|                std::abort();
  220|      0|            }
  221|  16.2k|            return chunk.value();
  222|  16.2k|        }
_ZN3uWS13ChunkIteratorppEv:
  228|  16.2k|        ChunkIterator &operator++() {
  229|  16.2k|            chunk = uWS::getNextChunk(*data, *state, trailer);
  230|  16.2k|            return *this;
  231|  16.2k|        }
_ZN3uWS31isParsingInvalidChunkedEncodingEm:
   99|  22.1k|    inline bool isParsingInvalidChunkedEncoding(uint64_t state) {
  100|  22.1k|        return state == STATE_IS_ERROR;
  101|  22.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:
  583|  90.9k|    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) {
  584|       |
  585|       |        /* This resets BloomFilter by construction, but later we also reset it again.
  586|       |         * Optimize this to skip resetting twice (req could be made global) */
  587|  90.9k|        HttpRequest req;
  588|       |
  589|  90.9k|        if (remainingStreamingBytes) {
  ------------------
  |  Branch (589:13): [True: 15.0k, False: 75.8k]
  ------------------
  590|       |
  591|       |            /* It's either chunked or with a content-length */
  592|  15.0k|            if (isParsingChunkedEncoding(remainingStreamingBytes)) {
  ------------------
  |  Branch (592:17): [True: 13.9k, False: 1.15k]
  ------------------
  593|  13.9k|                std::string_view dataToConsume(data, length);
  594|  13.9k|                for (auto chunk : uWS::ChunkIterator(&dataToConsume, &remainingStreamingBytes)) {
  ------------------
  |  Branch (594:33): [True: 13.1k, False: 13.9k]
  ------------------
  595|  13.1k|                    dataHandler(user, chunk, chunk.length() == 0);
  596|  13.1k|                }
  597|  13.9k|                if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) {
  ------------------
  |  Branch (597:21): [True: 322, False: 13.5k]
  ------------------
  598|    322|                    return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  599|    322|                }
  600|  13.5k|                data = (char *) dataToConsume.data();
  601|  13.5k|                length = (unsigned int) dataToConsume.length();
  602|  13.5k|            } else {
  603|       |                // this is exactly the same as below!
  604|       |                // todo: refactor this
  605|  1.15k|                if (remainingStreamingBytes >= length) {
  ------------------
  |  Branch (605:21): [True: 655, False: 501]
  ------------------
  606|    655|                    void *returnedUser = dataHandler(user, std::string_view(data, length), remainingStreamingBytes == length);
  607|    655|                    remainingStreamingBytes -= length;
  608|    655|                    return {0, returnedUser};
  609|    655|                } else {
  610|    501|                    void *returnedUser = dataHandler(user, std::string_view(data, remainingStreamingBytes), true);
  611|       |
  612|    501|                    data += (unsigned int) remainingStreamingBytes;
  613|    501|                    length -= (unsigned int) remainingStreamingBytes;
  614|       |
  615|    501|                    remainingStreamingBytes = 0;
  616|       |
  617|    501|                    if (returnedUser != user) {
  ------------------
  |  Branch (617:25): [True: 0, False: 501]
  ------------------
  618|      0|                        return {0, returnedUser};
  619|      0|                    }
  620|    501|                }
  621|  1.15k|            }
  622|       |
  623|  75.8k|        } else if (fallback.length()) {
  ------------------
  |  Branch (623:20): [True: 7.06k, False: 68.7k]
  ------------------
  624|  7.06k|            unsigned int had = (unsigned int) fallback.length();
  625|       |
  626|  7.06k|            size_t maxCopyDistance = std::min<size_t>(MAX_FALLBACK_SIZE - fallback.length(), (size_t) length);
  627|       |
  628|       |            /* We don't want fallback to be short string optimized, since we want to move it */
  629|  7.06k|            fallback.reserve(fallback.length() + maxCopyDistance + std::max<unsigned int>(MINIMUM_HTTP_POST_PADDING, sizeof(std::string)));
  630|  7.06k|            fallback.append(data, maxCopyDistance);
  631|       |
  632|       |            // break here on break
  633|  7.06k|            std::pair<unsigned int, void *> consumed = fenceAndConsumePostPadded<true>(fallback.data(), (unsigned int) fallback.length(), user, reserved, &req, requestHandler, dataHandler);
  634|  7.06k|            if (consumed.second != user) {
  ------------------
  |  Branch (634:17): [True: 2.52k, False: 4.54k]
  ------------------
  635|  2.52k|                return consumed;
  636|  2.52k|            }
  637|       |
  638|  4.54k|            if (consumed.first) {
  ------------------
  |  Branch (638:17): [True: 1.93k, False: 2.60k]
  ------------------
  639|       |
  640|       |                /* This logic assumes that we consumed everything in fallback buffer.
  641|       |                 * This is critically important, as we will get an integer overflow in case
  642|       |                 * of "had" being larger than what we consumed, and that we would drop data */
  643|  1.93k|                fallback.clear();
  644|  1.93k|                data += consumed.first - had;
  645|  1.93k|                length -= consumed.first - had;
  646|       |
  647|  1.93k|                if (remainingStreamingBytes) {
  ------------------
  |  Branch (647:21): [True: 1.18k, False: 748]
  ------------------
  648|       |                    /* It's either chunked or with a content-length */
  649|  1.18k|                    if (isParsingChunkedEncoding(remainingStreamingBytes)) {
  ------------------
  |  Branch (649:25): [True: 676, False: 512]
  ------------------
  650|    676|                        std::string_view dataToConsume(data, length);
  651|    971|                        for (auto chunk : uWS::ChunkIterator(&dataToConsume, &remainingStreamingBytes)) {
  ------------------
  |  Branch (651:41): [True: 971, False: 676]
  ------------------
  652|    971|                            dataHandler(user, chunk, chunk.length() == 0);
  653|    971|                        }
  654|    676|                        if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) {
  ------------------
  |  Branch (654:29): [True: 35, False: 641]
  ------------------
  655|     35|                            return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  656|     35|                        }
  657|    641|                        data = (char *) dataToConsume.data();
  658|    641|                        length = (unsigned int) dataToConsume.length();
  659|    641|                    } else {
  660|       |                        // this is exactly the same as above!
  661|    512|                        if (remainingStreamingBytes >= (unsigned int) length) {
  ------------------
  |  Branch (661:29): [True: 302, False: 210]
  ------------------
  662|    302|                            void *returnedUser = dataHandler(user, std::string_view(data, length), remainingStreamingBytes == (unsigned int) length);
  663|    302|                            remainingStreamingBytes -= length;
  664|    302|                            return {0, returnedUser};
  665|    302|                        } else {
  666|    210|                            void *returnedUser = dataHandler(user, std::string_view(data, remainingStreamingBytes), true);
  667|       |
  668|    210|                            data += (unsigned int) remainingStreamingBytes;
  669|    210|                            length -= (unsigned int) remainingStreamingBytes;
  670|       |
  671|    210|                            remainingStreamingBytes = 0;
  672|       |
  673|    210|                            if (returnedUser != user) {
  ------------------
  |  Branch (673:33): [True: 0, False: 210]
  ------------------
  674|      0|                                return {0, returnedUser};
  675|      0|                            }
  676|    210|                        }
  677|    512|                    }
  678|  1.18k|                }
  679|       |
  680|  2.60k|            } else {
  681|  2.60k|                if (fallback.length() == MAX_FALLBACK_SIZE) {
  ------------------
  |  Branch (681:21): [True: 748, False: 1.85k]
  ------------------
  682|    748|                    return {HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE, FULLPTR};
  683|    748|                }
  684|  1.85k|                return {0, user};
  685|  2.60k|            }
  686|  4.54k|        }
  687|       |
  688|  84.4k|        std::pair<unsigned int, void *> consumed = fenceAndConsumePostPadded<false>(data, length, user, reserved, &req, requestHandler, dataHandler);
  689|  84.4k|        if (consumed.second != user) {
  ------------------
  |  Branch (689:13): [True: 66.9k, False: 17.5k]
  ------------------
  690|  66.9k|            return consumed;
  691|  66.9k|        }
  692|       |
  693|  17.5k|        data += consumed.first;
  694|  17.5k|        length -= consumed.first;
  695|       |
  696|  17.5k|        if (length) {
  ------------------
  |  Branch (696:13): [True: 2.54k, False: 15.0k]
  ------------------
  697|  2.54k|            if (length < MAX_FALLBACK_SIZE) {
  ------------------
  |  Branch (697:17): [True: 2.49k, False: 45]
  ------------------
  698|  2.49k|                fallback.append(data, length);
  699|  2.49k|            } else {
  700|     45|                return {HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE, FULLPTR};
  701|     45|            }
  702|  2.54k|        }
  703|       |
  704|       |        // added for now
  705|  17.5k|        return {0, user};
  706|  17.5k|    }
_ZN3uWS10HttpParser25fenceAndConsumePostPaddedILi1EEENSt3__14pairIjPvEEPcjS4_S4_PNS_11HttpRequestERN5ofats13any_invocableIFS4_S4_S8_EEERNSA_IFS4_S4_NS2_17basic_string_viewIcNS2_11char_traitsIcEEEEbEEE:
  448|  7.06k|    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) {
  449|       |
  450|       |        /* How much data we CONSUMED (to throw away) */
  451|  7.06k|        unsigned int consumedTotal = 0;
  452|  7.06k|        unsigned int err = 0;
  453|       |
  454|       |        /* Fence two bytes past end of our buffer (buffer has post padded margins).
  455|       |         * This is to always catch scan for \r but not for \r\n. */
  456|  7.06k|        data[length] = '\r';
  457|  7.06k|        data[length + 1] = 'a'; /* Anything that is not \n, to trigger "invalid request" */
  458|       |
  459|  7.06k|        for (unsigned int consumed; length && (consumed = getHeaders(data, data + length, req->headers, reserved, err)); ) {
  ------------------
  |  Branch (459:37): [True: 7.06k, False: 0]
  |  Branch (459:47): [True: 4.46k, False: 2.60k]
  ------------------
  460|  4.46k|            data += consumed;
  461|  4.46k|            length -= consumed;
  462|  4.46k|            consumedTotal += consumed;
  463|       |
  464|       |            /* Even if we could parse it, check for length here as well */
  465|  4.46k|            if (consumed > MAX_FALLBACK_SIZE) {
  ------------------
  |  Branch (465:17): [True: 0, False: 4.46k]
  ------------------
  466|      0|                return {HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE, FULLPTR};
  467|      0|            }
  468|       |
  469|       |            /* Store HTTP version (ancient 1.0 or 1.1) */
  470|  4.46k|            req->ancientHttp = false;
  471|       |
  472|       |            /* Add all headers to bloom filter */
  473|  4.46k|            req->bf.reset();
  474|  17.6k|            for (HttpRequest::Header *h = req->headers; (++h)->key.length(); ) {
  ------------------
  |  Branch (474:57): [True: 13.1k, False: 4.46k]
  ------------------
  475|  13.1k|                req->bf.add(h->key);
  476|  13.1k|            }
  477|       |            
  478|       |            /* Break if no host header (but we can have empty string which is different from nullptr) */
  479|  4.46k|            if (!req->getHeader("host").data()) {
  ------------------
  |  Branch (479:17): [True: 2.19k, False: 2.27k]
  ------------------
  480|  2.19k|                return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  481|  2.19k|            }
  482|       |
  483|       |            /* RFC 9112 6.3
  484|       |            * If a message is received with both a Transfer-Encoding and a Content-Length header field,
  485|       |            * the Transfer-Encoding overrides the Content-Length. Such a message might indicate an attempt
  486|       |            * to perform request smuggling (Section 11.2) or response splitting (Section 11.1) and
  487|       |            * ought to be handled as an error. */
  488|  2.27k|            std::string_view transferEncodingString = req->getHeader("transfer-encoding");
  489|  2.27k|            std::string_view contentLengthString = req->getHeader("content-length");
  490|  2.27k|            if (transferEncodingString.length() && contentLengthString.length()) {
  ------------------
  |  Branch (490:17): [True: 963, False: 1.31k]
  |  Branch (490:52): [True: 274, False: 689]
  ------------------
  491|       |                /* Returning fullptr is the same as calling the errorHandler */
  492|       |                /* We could be smart and set an error in the context along with this, to indicate what 
  493|       |                 * http error response we might want to return */
  494|    274|                return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  495|    274|            }
  496|       |
  497|       |            /* Parse query */
  498|  2.00k|            const char *querySeparatorPtr = (const char *) memchr(req->headers->value.data(), '?', req->headers->value.length());
  499|  2.00k|            req->querySeparator = (unsigned int) ((querySeparatorPtr ? querySeparatorPtr : req->headers->value.data() + req->headers->value.length()) - req->headers->value.data());
  ------------------
  |  Branch (499:52): [True: 515, False: 1.48k]
  ------------------
  500|       |
  501|       |            /* If returned socket is not what we put in we need
  502|       |             * to break here as we either have upgraded to
  503|       |             * WebSockets or otherwise closed the socket. */
  504|  2.00k|            void *returnedUser = requestHandler(user, req);
  505|  2.00k|            if (returnedUser != user) {
  ------------------
  |  Branch (505:17): [True: 21, False: 1.97k]
  ------------------
  506|       |                /* We are upgraded to WebSocket or otherwise broken */
  507|     21|                return {consumedTotal, returnedUser};
  508|     21|            }
  509|       |
  510|       |            /* The rules at play here according to RFC 9112 for requests are essentially:
  511|       |             * If both content-length and transfer-encoding then invalid message; must break.
  512|       |             * If has transfer-encoding then must be chunked regardless of value.
  513|       |             * If content-length then fixed length even if 0.
  514|       |             * If none of the above then fixed length is 0. */
  515|       |
  516|       |            /* RFC 9112 6.3
  517|       |             * If a message is received with both a Transfer-Encoding and a Content-Length header field,
  518|       |             * the Transfer-Encoding overrides the Content-Length. */
  519|  1.97k|            if (transferEncodingString.length()) {
  ------------------
  |  Branch (519:17): [True: 676, False: 1.30k]
  ------------------
  520|       |
  521|       |                /* If a proxy sent us the transfer-encoding header that 100% means it must be chunked or else the proxy is
  522|       |                 * not RFC 9112 compliant. Therefore it is always better to assume this is the case, since that entirely eliminates 
  523|       |                 * all forms of transfer-encoding obfuscation tricks. We just rely on the header. */
  524|       |
  525|       |                /* RFC 9112 6.3
  526|       |                 * If a Transfer-Encoding header field is present in a request and the chunked transfer coding is not the
  527|       |                 * final encoding, the message body length cannot be determined reliably; the server MUST respond with the
  528|       |                 * 400 (Bad Request) status code and then close the connection. */
  529|       |
  530|       |                /* In this case we fail later by having the wrong interpretation (assuming chunked).
  531|       |                 * This could be made stricter but makes no difference either way, unless forwarding the identical message as a proxy. */
  532|       |
  533|    676|                remainingStreamingBytes = STATE_IS_CHUNKED;
  534|       |                /* If consume minimally, we do not want to consume anything but we want to mark this as being chunked */
  535|    676|                if (!CONSUME_MINIMALLY) {
  ------------------
  |  Branch (535:21): [Folded - Ignored]
  ------------------
  536|       |                    /* Go ahead and parse it (todo: better heuristics for emitting FIN to the app level) */
  537|      0|                    std::string_view dataToConsume(data, length);
  538|      0|                    for (auto chunk : uWS::ChunkIterator(&dataToConsume, &remainingStreamingBytes)) {
  ------------------
  |  Branch (538:37): [True: 0, False: 0]
  ------------------
  539|      0|                        dataHandler(user, chunk, chunk.length() == 0);
  540|      0|                    }
  541|      0|                    if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) {
  ------------------
  |  Branch (541:25): [True: 0, False: 0]
  ------------------
  542|      0|                        return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  543|      0|                    }
  544|      0|                    unsigned int consumed = (length - (unsigned int) dataToConsume.length());
  545|      0|                    data = (char *) dataToConsume.data();
  546|      0|                    length = (unsigned int) dataToConsume.length();
  547|      0|                    consumedTotal += consumed;
  548|      0|                }
  549|  1.30k|            } else if (contentLengthString.length()) {
  ------------------
  |  Branch (549:24): [True: 735, False: 568]
  ------------------
  550|    735|                remainingStreamingBytes = toUnsignedInteger(contentLengthString);
  551|    735|                if (remainingStreamingBytes == UINT64_MAX) {
  ------------------
  |  Branch (551:21): [True: 43, False: 692]
  ------------------
  552|       |                    /* Parser error */
  553|     43|                    return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  554|     43|                }
  555|       |
  556|    692|                if (!CONSUME_MINIMALLY) {
  ------------------
  |  Branch (556:21): [Folded - Ignored]
  ------------------
  557|      0|                    unsigned int emittable = (unsigned int) std::min<uint64_t>(remainingStreamingBytes, length);
  558|      0|                    dataHandler(user, std::string_view(data, emittable), emittable == remainingStreamingBytes);
  559|      0|                    remainingStreamingBytes -= emittable;
  560|       |
  561|      0|                    data += emittable;
  562|      0|                    length -= emittable;
  563|      0|                    consumedTotal += emittable;
  564|      0|                }
  565|    692|            } else {
  566|       |                /* If we came here without a body; emit an empty data chunk to signal no data */
  567|    568|                dataHandler(user, {}, true);
  568|    568|            }
  569|       |
  570|       |            /* Consume minimally should break as easrly as possible */
  571|  1.93k|            if (CONSUME_MINIMALLY) {
  ------------------
  |  Branch (571:17): [Folded - Ignored]
  ------------------
  572|  1.93k|                break;
  573|  1.93k|            }
  574|  1.93k|        }
  575|       |        /* Whenever we return FULLPTR, the interpretation of "consumed" should be the HttpError enum. */
  576|  4.54k|        if (err) {
  ------------------
  |  Branch (576:13): [True: 0, False: 4.54k]
  ------------------
  577|      0|            return {err, FULLPTR};
  578|      0|        }
  579|  4.54k|        return {consumedTotal, user};
  580|  4.54k|    }
_ZN3uWS10HttpParser10getHeadersEPcS1_PNS_11HttpRequest6HeaderEPvRj:
  337|  83.8k|    static unsigned int getHeaders(char *postPaddedBuffer, char *end, struct HttpRequest::Header *headers, void *reserved, unsigned int &err) {
  338|  83.8k|        char *preliminaryKey, *preliminaryValue, *start = postPaddedBuffer;
  339|       |
  340|       |        #ifdef UWS_WITH_PROXY
  341|       |            /* ProxyParser is passed as reserved parameter */
  342|       |            ProxyParser *pp = (ProxyParser *) reserved;
  343|       |
  344|       |            /* Parse PROXY protocol */
  345|       |            auto [done, offset] = pp->parse({postPaddedBuffer, (size_t) (end - postPaddedBuffer)});
  346|       |            if (!done) {
  347|       |                /* We do not reset the ProxyParser (on filure) since it is tied to this
  348|       |                * connection, which is really only supposed to ever get one PROXY frame
  349|       |                * anyways. We do however allow multiple PROXY frames to be sent (overwrites former). */
  350|       |                return 0;
  351|       |            } else {
  352|       |                /* We have consumed this data so skip it */
  353|       |                postPaddedBuffer += offset;
  354|       |            }
  355|       |        #else
  356|       |            /* This one is unused */
  357|  83.8k|            (void) reserved;
  358|  83.8k|            (void) end;
  359|  83.8k|        #endif
  360|       |
  361|       |        /* It is critical for fallback buffering logic that we only return with success
  362|       |         * if we managed to parse a complete HTTP request (minus data). Returning success
  363|       |         * for PROXY means we can end up succeeding, yet leaving bytes in the fallback buffer
  364|       |         * which is then removed, and our counters to flip due to overflow and we end up with a crash */
  365|       |
  366|       |        /* The request line is different from the field names / field values */
  367|  83.8k|        if (!(postPaddedBuffer = consumeRequestLine(postPaddedBuffer, headers[0]))) {
  ------------------
  |  Branch (367:13): [True: 65.6k, False: 18.2k]
  ------------------
  368|       |            /* Error - invalid request line */
  369|       |            /* Assuming it is 505 HTTP Version Not Supported */
  370|  65.6k|            err = HTTP_ERROR_505_HTTP_VERSION_NOT_SUPPORTED;
  371|  65.6k|            return 0;
  372|  65.6k|        }
  373|  18.2k|        headers++;
  374|       |
  375|  55.6k|        for (unsigned int i = 1; i < UWS_HTTP_MAX_HEADERS_COUNT - 1; i++) {
  ------------------
  |  |   53|  55.6k|#define UWS_HTTP_MAX_HEADERS_COUNT 100
  ------------------
  |  Branch (375:34): [True: 55.4k, False: 194]
  ------------------
  376|       |            /* Lower case and consume the field name */
  377|  55.4k|            preliminaryKey = postPaddedBuffer;
  378|  55.4k|            postPaddedBuffer = (char *) consumeFieldName(postPaddedBuffer);
  379|  55.4k|            headers->key = std::string_view(preliminaryKey, (size_t) (postPaddedBuffer - preliminaryKey));
  380|       |
  381|       |            /* We should not accept whitespace between key and colon, so colon must foloow immediately */
  382|  55.4k|            if (postPaddedBuffer[0] != ':') {
  ------------------
  |  Branch (382:17): [True: 1.59k, False: 53.8k]
  ------------------
  383|       |                /* Error: invalid chars in field name */
  384|  1.59k|                return 0;
  385|  1.59k|            }
  386|  53.8k|            postPaddedBuffer++;
  387|       |
  388|  53.8k|            preliminaryValue = postPaddedBuffer;
  389|       |            /* The goal of this call is to find next "\r\n", or any invalid field value chars, fast */
  390|  55.9k|            while (true) {
  ------------------
  |  Branch (390:20): [Folded - Ignored]
  ------------------
  391|  55.9k|                postPaddedBuffer = (char *) tryConsumeFieldValue(postPaddedBuffer);
  392|       |                /* If this is not CR then we caught some stinky invalid char on the way */
  393|  55.9k|                if (postPaddedBuffer[0] != '\r') {
  ------------------
  |  Branch (393:21): [True: 2.78k, False: 53.1k]
  ------------------
  394|       |                    /* If TAB then keep searching */
  395|  2.78k|                    if (postPaddedBuffer[0] == '\t') {
  ------------------
  |  Branch (395:25): [True: 2.03k, False: 742]
  ------------------
  396|  2.03k|                        postPaddedBuffer++;
  397|  2.03k|                        continue;
  398|  2.03k|                    }
  399|       |                    /* Error - invalid chars in field value */
  400|    742|                    return 0;
  401|  2.78k|                }
  402|  53.1k|                break;
  403|  55.9k|            }
  404|       |            /* We fence end[0] with \r, followed by end[1] being something that is "not \n", to signify "not found".
  405|       |                * This way we can have this one single check to see if we found \r\n WITHIN our allowed search space. */
  406|  53.1k|            if (postPaddedBuffer[1] == '\n') {
  ------------------
  |  Branch (406:17): [True: 51.2k, False: 1.91k]
  ------------------
  407|       |                /* Store this header, it is valid */
  408|  51.2k|                headers->value = std::string_view(preliminaryValue, (size_t) (postPaddedBuffer - preliminaryValue));
  409|  51.2k|                postPaddedBuffer += 2;
  410|       |
  411|       |                /* Trim trailing whitespace (SP, HTAB) */
  412|  55.3k|                while (headers->value.length() && headers->value.back() < 33) {
  ------------------
  |  Branch (412:24): [True: 20.2k, False: 35.0k]
  |  Branch (412:51): [True: 4.10k, False: 16.1k]
  ------------------
  413|  4.10k|                    headers->value.remove_suffix(1);
  414|  4.10k|                }
  415|       |
  416|       |                /* Trim initial whitespace (SP, HTAB) */
  417|  57.7k|                while (headers->value.length() && headers->value.front() < 33) {
  ------------------
  |  Branch (417:24): [True: 22.7k, False: 35.0k]
  |  Branch (417:51): [True: 6.56k, False: 16.1k]
  ------------------
  418|  6.56k|                    headers->value.remove_prefix(1);
  419|  6.56k|                }
  420|       |                
  421|  51.2k|                headers++;
  422|       |
  423|       |                /* We definitely have at least one header (or request line), so check if we are done */
  424|  51.2k|                if (*postPaddedBuffer == '\r') {
  ------------------
  |  Branch (424:21): [True: 13.7k, False: 37.4k]
  ------------------
  425|  13.7k|                    if (postPaddedBuffer[1] == '\n') {
  ------------------
  |  Branch (425:25): [True: 13.0k, False: 700]
  ------------------
  426|       |                        /* This cann take the very last header space */
  427|  13.0k|                        headers->key = std::string_view(nullptr, 0);
  428|  13.0k|                        return (unsigned int) ((postPaddedBuffer + 2) - start);
  429|  13.0k|                    } else {
  430|       |                        /* \r\n\r plus non-\n letter is malformed request, or simply out of search space */
  431|    700|                        return 0;
  432|    700|                    }
  433|  13.7k|                }
  434|  51.2k|            } else {
  435|       |                /* We are either out of search space or this is a malformed request */
  436|  1.91k|                return 0;
  437|  1.91k|            }
  438|  53.1k|        }
  439|       |        /* We ran out of header space, too large request */
  440|    194|        return 0;
  441|  18.2k|    }
_ZN3uWS10HttpParser18consumeRequestLineEPcRNS_11HttpRequest6HeaderE:
  293|  83.8k|    static inline char *consumeRequestLine(char *data, HttpRequest::Header &header) {
  294|       |        /* Scan until single SP, assume next is / (origin request) */
  295|  83.8k|        char *start = data;
  296|       |        /* This catches the post padded CR and fails */
  297|  2.16M|        while (data[0] > 32) data++;
  ------------------
  |  Branch (297:16): [True: 2.07M, False: 83.8k]
  ------------------
  298|  83.8k|        if (data[0] == 32 && data[1] == '/') {
  ------------------
  |  Branch (298:13): [True: 18.8k, False: 64.9k]
  |  Branch (298:30): [True: 18.5k, False: 334]
  ------------------
  299|  18.5k|            header.key = {start, (size_t) (data - start)};
  300|  18.5k|            data++;
  301|       |            /* Scan for less than 33 (catches post padded CR and fails) */
  302|  18.5k|            start = data;
  303|   342k|            for (; true; data += 8) {
  ------------------
  |  Branch (303:20): [Folded - Ignored]
  ------------------
  304|   342k|                uint64_t word;
  305|   342k|                memcpy(&word, data, sizeof(uint64_t));
  306|   342k|                if (hasLess(word, 33)) {
  ------------------
  |  Branch (306:21): [True: 18.5k, False: 323k]
  ------------------
  307|  77.8k|                    while (*(unsigned char *)data > 32) data++;
  ------------------
  |  Branch (307:28): [True: 59.2k, False: 18.5k]
  ------------------
  308|       |                    /* Now we stand on space */
  309|  18.5k|                    header.value = {start, (size_t) (data - start)};
  310|       |                    /* Check that the following is http 1.1 */
  311|  18.5k|                    if (memcmp(" HTTP/1.1\r\n", data, 11) == 0) {
  ------------------
  |  Branch (311:25): [True: 18.2k, False: 352]
  ------------------
  312|  18.2k|                        return data + 11;
  313|  18.2k|                    }
  314|    352|                    return nullptr;
  315|  18.5k|                }
  316|   342k|            }
  317|  18.5k|        }
  318|  65.2k|        return nullptr;
  319|  83.8k|    }
_ZN3uWS10HttpParser7hasLessEmm:
  220|  1.59M|    static inline uint64_t hasLess(uint64_t x, uint64_t n) {
  221|  1.59M|        return (((x)-~0ULL/255*(n))&~(x)&~0ULL/255*128);
  222|  1.59M|    }
_ZN3uWS10HttpParser16consumeFieldNameEPc:
  264|  55.4k|    static inline void *consumeFieldName(char *p) {
  265|       |        /* Best case fast path (particularly useful with clang) */
  266|  72.3k|        while (true) {
  ------------------
  |  Branch (266:16): [Folded - Ignored]
  ------------------
  267|  82.4k|            while ((*p >= 65) & (*p <= 90)) [[likely]] {
  ------------------
  |  Branch (267:20): [True: 10.1k, False: 72.3k]
  ------------------
  268|  10.1k|                *p |= 32;
  269|  10.1k|                p++;
  270|  10.1k|            }
  271|   276k|            while (((*p >= 97) & (*p <= 122))) [[likely]] {
  ------------------
  |  Branch (271:20): [True: 204k, False: 72.3k]
  ------------------
  272|   204k|                p++;
  273|   204k|            }
  274|  72.3k|            if (*p == ':') {
  ------------------
  |  Branch (274:17): [True: 51.6k, False: 20.6k]
  ------------------
  275|  51.6k|                return (void *)p;
  276|  51.6k|            }
  277|  20.6k|            if (*p == '-') {
  ------------------
  |  Branch (277:17): [True: 9.67k, False: 11.0k]
  ------------------
  278|  9.67k|                p++;
  279|  11.0k|            } else if (!((*p >= 65) & (*p <= 90))) {
  ------------------
  |  Branch (279:24): [True: 3.83k, False: 7.17k]
  ------------------
  280|       |                /* Exit fast path parsing */
  281|  3.83k|                break;
  282|  3.83k|            }
  283|  20.6k|        }
  284|       |
  285|       |        /* Generic */
  286|  79.7k|        while (isFieldNameByteFastLowercased(*(unsigned char *)p)) {
  ------------------
  |  Branch (286:16): [True: 75.8k, False: 3.83k]
  ------------------
  287|  75.8k|            p++;
  288|  75.8k|        }
  289|  3.83k|        return (void *)p;
  290|  55.4k|    }
_ZN3uWS10HttpParser29isFieldNameByteFastLowercasedERh:
  249|  79.7k|    static inline bool isFieldNameByteFastLowercased(unsigned char &in) {
  250|       |        /* Most common is lowercase alpha and hyphen */
  251|  79.7k|        if (((in >= 97) & (in <= 122)) | (in == '-')) [[likely]] {
  ------------------
  |  Branch (251:13): [True: 53.6k, False: 26.0k]
  ------------------
  252|  53.6k|            return true;
  253|       |        /* Second is upper case alpha */
  254|  53.6k|        } else if ((in >= 65) & (in <= 90)) [[unlikely]] {
  ------------------
  |  Branch (254:20): [True: 2.54k, False: 23.4k]
  ------------------
  255|  2.54k|            in |= 32;
  256|  2.54k|            return true;
  257|       |        /* These are rarely used but still valid */
  258|  23.4k|        } else if (isUnlikelyFieldNameByte(in)) [[unlikely]] {
  ------------------
  |  Branch (258:20): [True: 19.6k, False: 3.83k]
  ------------------
  259|  19.6k|            return true;
  260|  19.6k|        }
  261|  3.83k|        return false;
  262|  79.7k|    }
_ZN3uWS10HttpParser23isUnlikelyFieldNameByteEh:
  243|  23.4k|    {
  244|       |        /* Digits and 14 of the 15 non-alphanum characters (lacking hyphen) */
  245|  23.4k|        return ((c == '~') | (c == '|') | (c == '`') | (c == '_') | (c == '^') | (c == '.') | (c == '+')
  ------------------
  |  Branch (245:16): [True: 2.53k, False: 20.9k]
  ------------------
  246|  23.4k|            | (c == '*') | (c == '!')) || ((c >= 48) & (c <= 57)) || ((c <= 39) & (c >= 35));
  ------------------
  |  Branch (246:43): [True: 8.71k, False: 12.2k]
  |  Branch (246:70): [True: 8.40k, False: 3.83k]
  ------------------
  247|  23.4k|    }
_ZN3uWS10HttpParser20tryConsumeFieldValueEPc:
  325|  55.9k|    static inline void *tryConsumeFieldValue(char *p) {
  326|  1.25M|        for (; true; p += 8) {
  ------------------
  |  Branch (326:16): [Folded - Ignored]
  ------------------
  327|  1.25M|            uint64_t word;
  328|  1.25M|            memcpy(&word, p, sizeof(uint64_t));
  329|  1.25M|            if (hasLess(word, 32)) {
  ------------------
  |  Branch (329:17): [True: 55.9k, False: 1.19M]
  ------------------
  330|   109k|                while (*(unsigned char *)p > 31) p++;
  ------------------
  |  Branch (330:24): [True: 53.7k, False: 55.9k]
  ------------------
  331|  55.9k|                return (void *)p;
  332|  55.9k|            }
  333|  1.25M|        }
  334|  55.9k|    }
_ZN3uWS11HttpRequest9getHeaderENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
  115|  44.2k|    std::string_view getHeader(std::string_view lowerCasedHeader) {
  116|  44.2k|        if (bf.mightHave(lowerCasedHeader)) {
  ------------------
  |  Branch (116:13): [True: 17.4k, False: 26.8k]
  ------------------
  117|  32.0k|            for (Header *h = headers; (++h)->key.length(); ) {
  ------------------
  |  Branch (117:39): [True: 30.1k, False: 1.97k]
  ------------------
  118|  30.1k|                if (h->key.length() == lowerCasedHeader.length() && !strncmp(h->key.data(), lowerCasedHeader.data(), lowerCasedHeader.length())) {
  ------------------
  |  Branch (118:21): [True: 17.0k, False: 13.0k]
  |  Branch (118:69): [True: 15.4k, False: 1.59k]
  ------------------
  119|  15.4k|                    return h->value;
  120|  15.4k|                }
  121|  30.1k|            }
  122|  17.4k|        }
  123|  28.7k|        return std::string_view(nullptr, 0);
  124|  44.2k|    }
_ZN3uWS10HttpParser17toUnsignedIntegerENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
  203|  1.56k|    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.56k|        if (str.length() > 18) {
  ------------------
  |  Branch (205:13): [True: 33, False: 1.53k]
  ------------------
  206|     33|            return UINT64_MAX;
  207|     33|        }
  208|       |
  209|  1.53k|        uint64_t unsignedIntegerValue = 0;
  210|  5.85k|        for (char c : str) {
  ------------------
  |  Branch (210:21): [True: 5.85k, False: 1.46k]
  ------------------
  211|       |            /* As long as the letter is 0-9 we cannot overflow. */
  212|  5.85k|            if (c < '0' || c > '9') {
  ------------------
  |  Branch (212:17): [True: 24, False: 5.83k]
  |  Branch (212:28): [True: 45, False: 5.78k]
  ------------------
  213|     69|                return UINT64_MAX;
  214|     69|            }
  215|  5.78k|            unsignedIntegerValue = unsignedIntegerValue * 10ull + ((unsigned int) c - (unsigned int) '0');
  216|  5.78k|        }
  217|  1.46k|        return unsignedIntegerValue;
  218|  1.53k|    }
_ZN3uWS10HttpParser25fenceAndConsumePostPaddedILi0EEENSt3__14pairIjPvEEPcjS4_S4_PNS_11HttpRequestERN5ofats13any_invocableIFS4_S4_S8_EEERNSA_IFS4_S4_NS2_17basic_string_viewIcNS2_11char_traitsIcEEEEbEEE:
  448|  84.4k|    std::pair<unsigned int, void *> fenceAndConsumePostPadded(char *data, unsigned int length, void *user, void *reserved, HttpRequest *req, MoveOnlyFunction<void *(void *, HttpRequest *)> &requestHandler, MoveOnlyFunction<void *(void *, std::string_view, bool)> &dataHandler) {
  449|       |
  450|       |        /* How much data we CONSUMED (to throw away) */
  451|  84.4k|        unsigned int consumedTotal = 0;
  452|  84.4k|        unsigned int err = 0;
  453|       |
  454|       |        /* Fence two bytes past end of our buffer (buffer has post padded margins).
  455|       |         * This is to always catch scan for \r but not for \r\n. */
  456|  84.4k|        data[length] = '\r';
  457|  84.4k|        data[length + 1] = 'a'; /* Anything that is not \n, to trigger "invalid request" */
  458|       |
  459|  91.7k|        for (unsigned int consumed; length && (consumed = getHeaders(data, data + length, req->headers, reserved, err)); ) {
  ------------------
  |  Branch (459:37): [True: 76.7k, False: 15.0k]
  |  Branch (459:47): [True: 8.59k, False: 68.1k]
  ------------------
  460|  8.59k|            data += consumed;
  461|  8.59k|            length -= consumed;
  462|  8.59k|            consumedTotal += consumed;
  463|       |
  464|       |            /* Even if we could parse it, check for length here as well */
  465|  8.59k|            if (consumed > MAX_FALLBACK_SIZE) {
  ------------------
  |  Branch (465:17): [True: 25, False: 8.57k]
  ------------------
  466|     25|                return {HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE, FULLPTR};
  467|     25|            }
  468|       |
  469|       |            /* Store HTTP version (ancient 1.0 or 1.1) */
  470|  8.57k|            req->ancientHttp = false;
  471|       |
  472|       |            /* Add all headers to bloom filter */
  473|  8.57k|            req->bf.reset();
  474|  22.3k|            for (HttpRequest::Header *h = req->headers; (++h)->key.length(); ) {
  ------------------
  |  Branch (474:57): [True: 13.7k, False: 8.57k]
  ------------------
  475|  13.7k|                req->bf.add(h->key);
  476|  13.7k|            }
  477|       |            
  478|       |            /* Break if no host header (but we can have empty string which is different from nullptr) */
  479|  8.57k|            if (!req->getHeader("host").data()) {
  ------------------
  |  Branch (479:17): [True: 287, False: 8.28k]
  ------------------
  480|    287|                return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  481|    287|            }
  482|       |
  483|       |            /* RFC 9112 6.3
  484|       |            * If a message is received with both a Transfer-Encoding and a Content-Length header field,
  485|       |            * the Transfer-Encoding overrides the Content-Length. Such a message might indicate an attempt
  486|       |            * to perform request smuggling (Section 11.2) or response splitting (Section 11.1) and
  487|       |            * ought to be handled as an error. */
  488|  8.28k|            std::string_view transferEncodingString = req->getHeader("transfer-encoding");
  489|  8.28k|            std::string_view contentLengthString = req->getHeader("content-length");
  490|  8.28k|            if (transferEncodingString.length() && contentLengthString.length()) {
  ------------------
  |  Branch (490:17): [True: 1.88k, False: 6.40k]
  |  Branch (490:52): [True: 195, False: 1.68k]
  ------------------
  491|       |                /* Returning fullptr is the same as calling the errorHandler */
  492|       |                /* We could be smart and set an error in the context along with this, to indicate what 
  493|       |                 * http error response we might want to return */
  494|    195|                return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  495|    195|            }
  496|       |
  497|       |            /* Parse query */
  498|  8.08k|            const char *querySeparatorPtr = (const char *) memchr(req->headers->value.data(), '?', req->headers->value.length());
  499|  8.08k|            req->querySeparator = (unsigned int) ((querySeparatorPtr ? querySeparatorPtr : req->headers->value.data() + req->headers->value.length()) - req->headers->value.data());
  ------------------
  |  Branch (499:52): [True: 2.41k, False: 5.67k]
  ------------------
  500|       |
  501|       |            /* If returned socket is not what we put in we need
  502|       |             * to break here as we either have upgraded to
  503|       |             * WebSockets or otherwise closed the socket. */
  504|  8.08k|            void *returnedUser = requestHandler(user, req);
  505|  8.08k|            if (returnedUser != user) {
  ------------------
  |  Branch (505:17): [True: 720, False: 7.36k]
  ------------------
  506|       |                /* We are upgraded to WebSocket or otherwise broken */
  507|    720|                return {consumedTotal, returnedUser};
  508|    720|            }
  509|       |
  510|       |            /* The rules at play here according to RFC 9112 for requests are essentially:
  511|       |             * If both content-length and transfer-encoding then invalid message; must break.
  512|       |             * If has transfer-encoding then must be chunked regardless of value.
  513|       |             * If content-length then fixed length even if 0.
  514|       |             * If none of the above then fixed length is 0. */
  515|       |
  516|       |            /* RFC 9112 6.3
  517|       |             * If a message is received with both a Transfer-Encoding and a Content-Length header field,
  518|       |             * the Transfer-Encoding overrides the Content-Length. */
  519|  7.36k|            if (transferEncodingString.length()) {
  ------------------
  |  Branch (519:17): [True: 1.66k, False: 5.70k]
  ------------------
  520|       |
  521|       |                /* If a proxy sent us the transfer-encoding header that 100% means it must be chunked or else the proxy is
  522|       |                 * not RFC 9112 compliant. Therefore it is always better to assume this is the case, since that entirely eliminates 
  523|       |                 * all forms of transfer-encoding obfuscation tricks. We just rely on the header. */
  524|       |
  525|       |                /* RFC 9112 6.3
  526|       |                 * If a Transfer-Encoding header field is present in a request and the chunked transfer coding is not the
  527|       |                 * final encoding, the message body length cannot be determined reliably; the server MUST respond with the
  528|       |                 * 400 (Bad Request) status code and then close the connection. */
  529|       |
  530|       |                /* In this case we fail later by having the wrong interpretation (assuming chunked).
  531|       |                 * This could be made stricter but makes no difference either way, unless forwarding the identical message as a proxy. */
  532|       |
  533|  1.66k|                remainingStreamingBytes = STATE_IS_CHUNKED;
  534|       |                /* If consume minimally, we do not want to consume anything but we want to mark this as being chunked */
  535|  1.66k|                if (!CONSUME_MINIMALLY) {
  ------------------
  |  Branch (535:21): [Folded - Ignored]
  ------------------
  536|       |                    /* Go ahead and parse it (todo: better heuristics for emitting FIN to the app level) */
  537|  1.66k|                    std::string_view dataToConsume(data, length);
  538|  2.14k|                    for (auto chunk : uWS::ChunkIterator(&dataToConsume, &remainingStreamingBytes)) {
  ------------------
  |  Branch (538:37): [True: 2.14k, False: 1.66k]
  ------------------
  539|  2.14k|                        dataHandler(user, chunk, chunk.length() == 0);
  540|  2.14k|                    }
  541|  1.66k|                    if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) {
  ------------------
  |  Branch (541:25): [True: 23, False: 1.64k]
  ------------------
  542|     23|                        return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  543|     23|                    }
  544|  1.64k|                    unsigned int consumed = (length - (unsigned int) dataToConsume.length());
  545|  1.64k|                    data = (char *) dataToConsume.data();
  546|  1.64k|                    length = (unsigned int) dataToConsume.length();
  547|  1.64k|                    consumedTotal += consumed;
  548|  1.64k|                }
  549|  5.70k|            } else if (contentLengthString.length()) {
  ------------------
  |  Branch (549:24): [True: 833, False: 4.87k]
  ------------------
  550|    833|                remainingStreamingBytes = toUnsignedInteger(contentLengthString);
  551|    833|                if (remainingStreamingBytes == UINT64_MAX) {
  ------------------
  |  Branch (551:21): [True: 59, False: 774]
  ------------------
  552|       |                    /* Parser error */
  553|     59|                    return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};
  554|     59|                }
  555|       |
  556|    774|                if (!CONSUME_MINIMALLY) {
  ------------------
  |  Branch (556:21): [Folded - Ignored]
  ------------------
  557|    774|                    unsigned int emittable = (unsigned int) std::min<uint64_t>(remainingStreamingBytes, length);
  558|    774|                    dataHandler(user, std::string_view(data, emittable), emittable == remainingStreamingBytes);
  559|    774|                    remainingStreamingBytes -= emittable;
  560|       |
  561|    774|                    data += emittable;
  562|    774|                    length -= emittable;
  563|    774|                    consumedTotal += emittable;
  564|    774|                }
  565|  4.87k|            } else {
  566|       |                /* If we came here without a body; emit an empty data chunk to signal no data */
  567|  4.87k|                dataHandler(user, {}, true);
  568|  4.87k|            }
  569|       |
  570|       |            /* Consume minimally should break as easrly as possible */
  571|  7.28k|            if (CONSUME_MINIMALLY) {
  ------------------
  |  Branch (571:17): [Folded - Ignored]
  ------------------
  572|      0|                break;
  573|      0|            }
  574|  7.28k|        }
  575|       |        /* Whenever we return FULLPTR, the interpretation of "consumed" should be the HttpError enum. */
  576|  83.1k|        if (err) {
  ------------------
  |  Branch (576:13): [True: 65.6k, False: 17.5k]
  ------------------
  577|  65.6k|            return {err, FULLPTR};
  578|  65.6k|        }
  579|  17.5k|        return {consumedTotal, user};
  580|  83.1k|    }
_ZN3uWS11HttpRequest6getUrlEv:
  126|  20.1k|    std::string_view getUrl() {
  127|  20.1k|        return std::string_view(headers->value.data(), querySeparator);
  128|  20.1k|    }
_ZN3uWS11HttpRequest9getMethodEv:
  139|  20.1k|    std::string_view getMethod() {
  140|       |        /* Compatibility hack: lower case method (todo: remove when major version bumps) */
  141|   105k|        for (unsigned int i = 0; i < headers->key.length(); i++) {
  ------------------
  |  Branch (141:34): [True: 85.5k, False: 20.1k]
  ------------------
  142|  85.5k|            ((char *) headers->key.data())[i] |= 32;
  143|  85.5k|        }
  144|       |
  145|  20.1k|        return std::string_view(headers->key.data(), headers->key.length());
  146|  20.1k|    }
_ZN3uWS11HttpRequest8getQueryEv:
  149|  10.0k|    std::string_view getQuery() {
  150|  10.0k|        if (querySeparator < headers->value.length()) {
  ------------------
  |  Branch (150:13): [True: 2.92k, False: 7.16k]
  ------------------
  151|       |            /* Strip the initial ? */
  152|  2.92k|            return std::string_view(headers->value.data() + querySeparator + 1, headers->value.length() - querySeparator - 1);
  153|  7.16k|        } else {
  154|  7.16k|            return std::string_view(nullptr, 0);
  155|  7.16k|        }
  156|  10.0k|    }
_ZN3uWS11HttpRequest8getQueryENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
  159|  20.1k|    std::string_view getQuery(std::string_view key) {
  160|       |        /* Raw querystring including initial '?' sign */
  161|  20.1k|        std::string_view queryString = std::string_view(headers->value.data() + querySeparator, headers->value.length() - querySeparator);
  162|       |
  163|  20.1k|        return getDecodedQueryValue(key, queryString);
  164|  20.1k|    }
_ZN3uWS11HttpRequest5beginEv:
  102|  9.34k|    HeaderIterator begin() {
  103|  9.34k|        return {headers + 1};
  104|  9.34k|    }
_ZN3uWS11HttpRequest3endEv:
  106|  9.34k|    HeaderIterator end() {
  107|  9.34k|        return {nullptr};
  108|  9.34k|    }
_ZNK3uWS11HttpRequest14HeaderIteratorneERKS1_:
   84|  27.1k|        bool operator!=(const HeaderIterator &other) const {
   85|       |            /* Comparison with end is a special case */
   86|  27.1k|            if (ptr != other.ptr) {
  ------------------
  |  Branch (86:17): [True: 27.1k, False: 0]
  ------------------
   87|  27.1k|                return other.ptr || ptr->key.length();
  ------------------
  |  Branch (87:24): [True: 0, False: 27.1k]
  |  Branch (87:37): [True: 17.7k, False: 9.34k]
  ------------------
   88|  27.1k|            }
   89|      0|            return false;
   90|  27.1k|        }
_ZNK3uWS11HttpRequest14HeaderIteratordeEv:
   97|  17.7k|        std::pair<std::string_view, std::string_view> operator*() const {
   98|  17.7k|            return {ptr->key, ptr->value};
   99|  17.7k|        }
_ZN3uWS11HttpRequest14HeaderIteratorppEv:
   92|  17.7k|        HeaderIterator &operator++() {
   93|  17.7k|            ptr++;
   94|  17.7k|            return *this;
   95|  17.7k|        }

_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:
  279|      8|    void add(std::vector<std::string> methods, std::string pattern, MoveOnlyFunction<bool(HttpRouter *)> &&handler, uint32_t priority = MEDIUM_PRIORITY) {
  280|       |        /* First remove existing handler */
  281|      8|        remove(methods[0], pattern, priority);
  282|       |        
  283|      8|        for (std::string method : methods) {
  ------------------
  |  Branch (283:33): [True: 8, False: 8]
  ------------------
  284|       |            /* Lookup method */
  285|      8|            Node *node = getNode(&root, method, false);
  286|       |            /* Iterate over all segments */
  287|      8|            setUrl(pattern);
  288|     22|            for (int i = 0; !getUrlSegment(i).second; i++) {
  ------------------
  |  Branch (288:29): [True: 14, False: 8]
  ------------------
  289|     14|                std::string strippedSegment(getUrlSegment(i).first);
  290|     14|                if (strippedSegment.length() && strippedSegment[0] == ':') {
  ------------------
  |  Branch (290:21): [True: 14, False: 0]
  |  Branch (290:49): [True: 8, False: 6]
  ------------------
  291|       |                    /* Parameter routes must be named only : */
  292|      8|                    strippedSegment = ":";
  293|      8|                }
  294|     14|                node = getNode(node, strippedSegment, priority == HIGH_PRIORITY);
  295|     14|            }
  296|       |            /* Insert handler in order sorted by priority (most significant 1 byte) */
  297|      8|            node->handlers.insert(std::upper_bound(node->handlers.begin(), node->handlers.end(), (uint32_t) (priority | handlers.size())), (uint32_t) (priority | handlers.size()));
  298|      8|        }
  299|       |
  300|       |        /* Alloate this handler */
  301|      8|        handlers.emplace_back(std::move(handler));
  302|       |
  303|       |        /* ANY method must be last, GET must be first */
  304|      8|        std::sort(root.children.begin(), root.children.end(), [](const auto &a, const auto &b) {
  305|       |            /* Assuming the list of methods is unique, non-repeating */
  306|      8|            if (a->name == "GET") {
  307|      8|                return true;
  308|      8|            } else if (b->name == "GET") {
  309|      8|                return false;
  310|      8|            } else if (a->name == ANY_METHOD_TOKEN) {
  311|      8|                return false;
  312|      8|            } else if (b->name == ANY_METHOD_TOKEN) {
  313|      8|                return true;
  314|      8|            } else {
  315|      8|                return a->name < b->name;
  316|      8|            }
  317|      8|        });
  318|      8|    }
_ZN3uWS10HttpRouterIN10StaticData10RouterDataEE6removeENSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESA_j:
  360|      8|    void remove(std::string method, std::string pattern, uint32_t priority) {
  361|      8|        uint32_t handler = findHandler(method, pattern, priority);
  362|      8|        if (handler == UINT32_MAX) {
  ------------------
  |  Branch (362:13): [True: 8, False: 0]
  ------------------
  363|       |            /* Not found or already removed, do nothing */
  364|      8|            return;
  365|      8|        }
  366|       |
  367|       |        /* Cull the entire tree */
  368|       |        /* For all nodes in depth first tree traveral;
  369|       |         * if node contains handler - remove the handler -
  370|       |         * if node holds no handlers after removal, remove the node and return */
  371|      0|        cullNode(nullptr, &root, handler);
  372|       |
  373|       |        /* Now remove the actual handler */
  374|      0|        handlers.erase(handlers.begin() + (handler & HANDLER_MASK));
  375|      0|    }
_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 (child->name == segment && child->isHighPriority == (priority == HIGH_PRIORITY)) {
  ------------------
  |  Branch (220:29): [True: 0, False: 6]
  |  Branch (220:55): [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|  10.1k|    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|  10.1k|        currentUrl = url;
  130|  10.1k|        urlSegmentTop = -1;
  131|  10.1k|    }
_ZN3uWS10HttpRouterIN10StaticData10RouterDataEE13getUrlSegmentEi:
  134|  24.3k|    inline std::pair<std::string_view, bool> getUrlSegment(int urlSegment) {
  135|  24.3k|        if (urlSegment > urlSegmentTop) {
  ------------------
  |  Branch (135:13): [True: 23.3k, False: 957]
  ------------------
  136|       |            /* Signal as STOP when we have no more URL or stack space */
  137|  23.3k|            if (!currentUrl.length() || urlSegment > int(MAX_URL_SEGMENTS - 1)) {
  ------------------
  |  Branch (137:17): [True: 8.31k, False: 15.0k]
  |  Branch (137:41): [True: 0, False: 15.0k]
  ------------------
  138|  8.31k|                return {{}, true};
  139|  8.31k|            }
  140|       |
  141|       |            /* We always stand on a slash here, so step over it */
  142|  15.0k|            currentUrl.remove_prefix(1);
  143|       |
  144|  15.0k|            auto segmentLength = currentUrl.find('/');
  145|  15.0k|            if (segmentLength == std::string::npos) {
  ------------------
  |  Branch (145:17): [True: 9.99k, False: 5.06k]
  ------------------
  146|  9.99k|                segmentLength = currentUrl.length();
  147|       |
  148|       |                /* Push to url segment vector */
  149|  9.99k|                urlSegmentVector[urlSegment] = currentUrl.substr(0, segmentLength);
  150|  9.99k|                urlSegmentTop++;
  151|       |
  152|       |                /* Update currentUrl */
  153|  9.99k|                currentUrl = currentUrl.substr(segmentLength);
  154|  9.99k|            } else {
  155|       |                /* Push to url segment vector */
  156|  5.06k|                urlSegmentVector[urlSegment] = currentUrl.substr(0, segmentLength);
  157|  5.06k|                urlSegmentTop++;
  158|       |
  159|       |                /* Update currentUrl */
  160|  5.06k|                currentUrl = currentUrl.substr(segmentLength);
  161|  5.06k|            }
  162|  15.0k|        }
  163|       |        /* In any case we return it */
  164|  16.0k|        return {urlSegmentVector[urlSegment], false};
  165|  24.3k|    }
_ZZN3uWS10HttpRouterIN10StaticData10RouterDataEE3addENSt3__16vectorINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEESB_ON5ofats13any_invocableIFbPS3_EEEjENKUlRKT_RKT0_E_clINS4_10unique_ptrINS3_4NodeENS4_14default_deleteIST_EEEESW_EEDaSM_SP_:
  304|     16|        std::sort(root.children.begin(), root.children.end(), [](const auto &a, const auto &b) {
  305|       |            /* Assuming the list of methods is unique, non-repeating */
  306|     16|            if (a->name == "GET") {
  ------------------
  |  Branch (306:17): [True: 0, False: 16]
  ------------------
  307|      0|                return true;
  308|     16|            } else if (b->name == "GET") {
  ------------------
  |  Branch (308:24): [True: 0, False: 16]
  ------------------
  309|      0|                return false;
  310|     16|            } else if (a->name == ANY_METHOD_TOKEN) {
  ------------------
  |  Branch (310:24): [True: 6, False: 10]
  ------------------
  311|      6|                return false;
  312|     10|            } else if (b->name == ANY_METHOD_TOKEN) {
  ------------------
  |  Branch (312:24): [True: 4, False: 6]
  ------------------
  313|      4|                return true;
  314|      6|            } else {
  315|      6|                return a->name < b->name;
  316|      6|            }
  317|     16|        });
_ZN3uWS10HttpRouterIN10StaticData10RouterDataEE13getParametersEv:
  248|  9.45k|    std::pair<int, std::string_view *> getParameters() {
  249|  9.45k|        return {routeParameters.paramsTop, routeParameters.params};
  250|  9.45k|    }
_ZN3uWS10HttpRouterIN10StaticData10RouterDataEE11getUserDataEv:
  252|  10.0k|    USERDATA &getUserData() {
  253|  10.0k|        return userData;
  254|  10.0k|    }
_ZN3uWS10HttpRouterIN10StaticData10RouterDataEE5routeENSt3__117basic_string_viewIcNS4_11char_traitsIcEEEES8_:
  257|  10.0k|    bool route(std::string_view method, std::string_view url) {
  258|       |        /* Reset url parsing cache */
  259|  10.0k|        setUrl(url);
  260|  10.0k|        routeParameters.reset();
  261|       |
  262|       |        /* Begin by finding the method node */
  263|  12.4k|        for (auto &p : root.children) {
  ------------------
  |  Branch (263:22): [True: 12.4k, False: 627]
  ------------------
  264|  12.4k|            if (p->name == method) {
  ------------------
  |  Branch (264:17): [True: 9.46k, False: 2.98k]
  ------------------
  265|       |                /* Then route the url */
  266|  9.46k|                if (executeHandlers(p.get(), 0, userData)) {
  ------------------
  |  Branch (266:21): [True: 9.34k, False: 114]
  ------------------
  267|  9.34k|                    return true;
  268|  9.34k|                } else {
  269|    114|                    break;
  270|    114|                }
  271|  9.46k|            }
  272|  12.4k|        }
  273|       |
  274|       |        /* Always test any route last */
  275|    741|        return executeHandlers(root.children.back().get(), 0, userData);
  276|  10.0k|    }
_ZN3uWS10HttpRouterIN10StaticData10RouterDataEE15RouteParameters5resetEv:
  108|  10.0k|        void reset() {
  109|  10.0k|            paramsTop = -1;
  110|  10.0k|        }
_ZN3uWS10HttpRouterIN10StaticData10RouterDataEE15executeHandlersEPNS3_4NodeEiRS2_:
  168|  24.2k|    bool executeHandlers(Node *parent, int urlSegment, USERDATA &userData) {
  169|       |
  170|  24.2k|        auto [segment, isStop] = getUrlSegment(urlSegment);
  171|       |
  172|       |        /* If we are on STOP, return where we may stand */
  173|  24.2k|        if (isStop) {
  ------------------
  |  Branch (173:13): [True: 8.31k, False: 15.9k]
  ------------------
  174|       |            /* We have reached accross the entire URL with no stoppage, execute */
  175|  8.31k|            for (uint32_t handler : parent->handlers) {
  ------------------
  |  Branch (175:35): [True: 8.24k, False: 61]
  ------------------
  176|  8.24k|                if (handlers[handler & HANDLER_MASK](this)) {
  ------------------
  |  Branch (176:21): [True: 8.24k, False: 0]
  ------------------
  177|  8.24k|                    return true;
  178|  8.24k|                }
  179|  8.24k|            }
  180|       |            /* We reached the end, so go back */
  181|     61|            return false;
  182|  8.31k|        }
  183|       |
  184|  17.3k|        for (auto &p : parent->children) {
  ------------------
  |  Branch (184:22): [True: 17.3k, False: 1.71k]
  ------------------
  185|  17.3k|            if (p->name.length() && p->name[0] == '*') {
  ------------------
  |  Branch (185:17): [True: 17.3k, False: 0]
  |  Branch (185:37): [True: 1.20k, False: 16.1k]
  ------------------
  186|       |                /* Wildcard match (can be seen as a shortcut) */
  187|  1.20k|                for (uint32_t handler : p->handlers) {
  ------------------
  |  Branch (187:39): [True: 1.20k, False: 108]
  ------------------
  188|  1.20k|                    if (handlers[handler & HANDLER_MASK](this)) {
  ------------------
  |  Branch (188:25): [True: 1.09k, False: 108]
  ------------------
  189|  1.09k|                        return true;
  190|  1.09k|                    }
  191|  1.20k|                }
  192|  16.1k|            } else if (p->name.length() && p->name[0] == ':' && segment.length()) {
  ------------------
  |  Branch (192:24): [True: 16.1k, False: 0]
  |  Branch (192:44): [True: 7.78k, False: 8.35k]
  |  Branch (192:65): [True: 7.73k, False: 44]
  ------------------
  193|       |                /* Parameter match */
  194|  7.73k|                routeParameters.push(segment);
  195|  7.73k|                if (executeHandlers(p.get(), urlSegment + 1, userData)) {
  ------------------
  |  Branch (195:21): [True: 7.64k, False: 91]
  ------------------
  196|  7.64k|                    return true;
  197|  7.64k|                }
  198|     91|                routeParameters.pop();
  199|  8.40k|            } else if (p->name == segment) {
  ------------------
  |  Branch (199:24): [True: 6.34k, False: 2.05k]
  ------------------
  200|       |                /* Static match */
  201|  6.34k|                if (executeHandlers(p.get(), urlSegment + 1, userData)) {
  ------------------
  |  Branch (201:21): [True: 5.52k, False: 825]
  ------------------
  202|  5.52k|                    return true;
  203|  5.52k|                }
  204|  6.34k|            }
  205|  17.3k|        }
  206|  1.71k|        return false;
  207|  15.9k|    }
_ZN3uWS10HttpRouterIN10StaticData10RouterDataEE15RouteParameters4pushENSt3__117basic_string_viewIcNS5_11char_traitsIcEEEE:
  112|  7.73k|        void push(std::string_view param) {
  113|       |            /* We check these bounds indirectly via the urlSegments limit */
  114|  7.73k|            params[++paramsTop] = param;
  115|  7.73k|        }
_ZN3uWS10HttpRouterIN10StaticData10RouterDataEE15RouteParameters3popEv:
  117|     91|        void pop() {
  118|       |            /* Same here, we cannot pop outside */
  119|     91|            paramsTop--;
  120|     91|        }

_ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEEC2EOS8_:
  188|     14|  any_invocable_impl(any_invocable_impl&& rhs) noexcept {
  189|     14|    if (rhs.handle_) {
  ------------------
  |  Branch (189:9): [True: 14, False: 0]
  ------------------
  190|     14|      handle_ = rhs.handle_;
  191|     14|      handle_(action::move, &storage_, &rhs.storage_);
  192|     14|      call_ = rhs.call_;
  193|     14|      rhs.handle_ = nullptr;
  194|     14|    }
  195|     14|  }
_ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEED2Ev:
  206|     14|  ~any_invocable_impl() { destroy(); }
_ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE7destroyEv:
  239|     14|  void destroy() noexcept {
  240|     14|    if (handle_) {
  ------------------
  |  Branch (240:9): [True: 0, False: 14]
  ------------------
  241|      0|      handle_(action::destroy, &storage_, nullptr);
  242|      0|      handle_ = nullptr;
  243|      0|    }
  244|     14|  }
_ZN5ofats13any_invocableIFbPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEEC2IZNS3_C1EvEUlPT_E_vEEOSA_:
  303|      2|    any_invocable(F&& f) {                                                     \
  304|      2|      base_type::template create<std::decay_t<F>>(std::forward<F>(f));         \
  305|      2|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEEC2Ev:
  186|      8|  any_invocable_impl() noexcept = default;
_ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE6createIZNS4_C1EvEUlPT_E_JSC_EEEvDpOT0_:
  232|      2|  void create(Args&&... args) {
  233|      2|    using hdl = handler<F>;
  234|      2|    hdl::create(storage_, std::forward<Args>(args)...);
  235|      2|    handle_ = &hdl::handle;
  236|      2|    call_ = &hdl::call;
  237|      2|  }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E_E6createIJSC_EEEvRNS0_7storageEDpOT_:
  118|      8|    static void create(storage& s, Args&&... args) {
  119|      8|      new (static_cast<void*>(&s.buf_)) T(std::forward<Args>(args)...);
  120|      8|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE12handler_baseINS8_13small_handlerIZNS4_C1EvEUlPT_E_EEE6handleENS0_6actionEPNS0_7storageESI_:
  103|      6|    static void handle(action act, storage* current, storage* other = nullptr) {
  104|      6|      switch (act) {
  ------------------
  |  Branch (104:15): [True: 0, False: 6]
  ------------------
  105|      0|        case (action::destroy):
  ------------------
  |  Branch (105:9): [True: 0, False: 6]
  ------------------
  106|      0|          Derived::destroy(*current);
  107|      0|          break;
  108|      6|        case (action::move):
  ------------------
  |  Branch (108:9): [True: 6, False: 0]
  ------------------
  109|      6|          Derived::move(*current, *other);
  110|      6|          break;
  111|      6|      }
  112|      6|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E_E7destroyERNS0_7storageE:
  122|      6|    static void destroy(storage& s) noexcept {
  123|      6|      T& value = *static_cast<T*>(static_cast<void*>(&s.buf_));
  124|      6|      value.~T();
  125|      6|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E_E4moveERNS0_7storageESF_:
  127|      6|    static void move(storage& dst, storage& src) noexcept {
  128|      6|      create(dst, std::move(*static_cast<T*>(static_cast<void*>(&src.buf_))));
  129|      6|      destroy(src);
  130|      6|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E_E4callERNS0_7storageES7_:
  132|  2.72k|    static R call(storage& s, ArgTypes... args) {
  133|  2.72k|      return std::invoke(*static_cast<T*>(static_cast<void*>(&s.buf_)),
  134|  2.72k|                         std::forward<ArgTypes>(args)...);
  135|  2.72k|    }
_ZN5ofats13any_invocableIFbPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEEC2IZNS3_C1EvEUlPT_E0_vEEOSA_:
  303|      2|    any_invocable(F&& f) {                                                     \
  304|      2|      base_type::template create<std::decay_t<F>>(std::forward<F>(f));         \
  305|      2|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE6createIZNS4_C1EvEUlPT_E0_JSC_EEEvDpOT0_:
  232|      2|  void create(Args&&... args) {
  233|      2|    using hdl = handler<F>;
  234|      2|    hdl::create(storage_, std::forward<Args>(args)...);
  235|      2|    handle_ = &hdl::handle;
  236|      2|    call_ = &hdl::call;
  237|      2|  }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E0_E6createIJSC_EEEvRNS0_7storageEDpOT_:
  118|      6|    static void create(storage& s, Args&&... args) {
  119|      6|      new (static_cast<void*>(&s.buf_)) T(std::forward<Args>(args)...);
  120|      6|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE12handler_baseINS8_13small_handlerIZNS4_C1EvEUlPT_E0_EEE6handleENS0_6actionEPNS0_7storageESI_:
  103|      4|    static void handle(action act, storage* current, storage* other = nullptr) {
  104|      4|      switch (act) {
  ------------------
  |  Branch (104:15): [True: 0, False: 4]
  ------------------
  105|      0|        case (action::destroy):
  ------------------
  |  Branch (105:9): [True: 0, False: 4]
  ------------------
  106|      0|          Derived::destroy(*current);
  107|      0|          break;
  108|      4|        case (action::move):
  ------------------
  |  Branch (108:9): [True: 4, False: 0]
  ------------------
  109|      4|          Derived::move(*current, *other);
  110|      4|          break;
  111|      4|      }
  112|      4|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E0_E7destroyERNS0_7storageE:
  122|      4|    static void destroy(storage& s) noexcept {
  123|      4|      T& value = *static_cast<T*>(static_cast<void*>(&s.buf_));
  124|      4|      value.~T();
  125|      4|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E0_E4moveERNS0_7storageESF_:
  127|      4|    static void move(storage& dst, storage& src) noexcept {
  128|      4|      create(dst, std::move(*static_cast<T*>(static_cast<void*>(&src.buf_))));
  129|      4|      destroy(src);
  130|      4|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E0_E4callERNS0_7storageES7_:
  132|  1.09k|    static R call(storage& s, ArgTypes... args) {
  133|  1.09k|      return std::invoke(*static_cast<T*>(static_cast<void*>(&s.buf_)),
  134|  1.09k|                         std::forward<ArgTypes>(args)...);
  135|  1.09k|    }
_ZN5ofats13any_invocableIFbPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEEC2IZNS3_C1EvEUlPT_E1_vEEOSA_:
  303|      2|    any_invocable(F&& f) {                                                     \
  304|      2|      base_type::template create<std::decay_t<F>>(std::forward<F>(f));         \
  305|      2|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE6createIZNS4_C1EvEUlPT_E1_JSC_EEEvDpOT0_:
  232|      2|  void create(Args&&... args) {
  233|      2|    using hdl = handler<F>;
  234|      2|    hdl::create(storage_, std::forward<Args>(args)...);
  235|      2|    handle_ = &hdl::handle;
  236|      2|    call_ = &hdl::call;
  237|      2|  }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E1_E6createIJSC_EEEvRNS0_7storageEDpOT_:
  118|      4|    static void create(storage& s, Args&&... args) {
  119|      4|      new (static_cast<void*>(&s.buf_)) T(std::forward<Args>(args)...);
  120|      4|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE12handler_baseINS8_13small_handlerIZNS4_C1EvEUlPT_E1_EEE6handleENS0_6actionEPNS0_7storageESI_:
  103|      2|    static void handle(action act, storage* current, storage* other = nullptr) {
  104|      2|      switch (act) {
  ------------------
  |  Branch (104:15): [True: 0, False: 2]
  ------------------
  105|      0|        case (action::destroy):
  ------------------
  |  Branch (105:9): [True: 0, False: 2]
  ------------------
  106|      0|          Derived::destroy(*current);
  107|      0|          break;
  108|      2|        case (action::move):
  ------------------
  |  Branch (108:9): [True: 2, False: 0]
  ------------------
  109|      2|          Derived::move(*current, *other);
  110|      2|          break;
  111|      2|      }
  112|      2|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E1_E7destroyERNS0_7storageE:
  122|      2|    static void destroy(storage& s) noexcept {
  123|      2|      T& value = *static_cast<T*>(static_cast<void*>(&s.buf_));
  124|      2|      value.~T();
  125|      2|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E1_E4moveERNS0_7storageESF_:
  127|      2|    static void move(storage& dst, storage& src) noexcept {
  128|      2|      create(dst, std::move(*static_cast<T*>(static_cast<void*>(&src.buf_))));
  129|      2|      destroy(src);
  130|      2|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E1_E4callERNS0_7storageES7_:
  132|    108|    static R call(storage& s, ArgTypes... args) {
  133|    108|      return std::invoke(*static_cast<T*>(static_cast<void*>(&s.buf_)),
  134|    108|                         std::forward<ArgTypes>(args)...);
  135|    108|    }
_ZN5ofats13any_invocableIFbPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEEC2IZNS3_C1EvEUlPT_E2_vEEOSA_:
  303|      2|    any_invocable(F&& f) {                                                     \
  304|      2|      base_type::template create<std::decay_t<F>>(std::forward<F>(f));         \
  305|      2|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE6createIZNS4_C1EvEUlPT_E2_JSC_EEEvDpOT0_:
  232|      2|  void create(Args&&... args) {
  233|      2|    using hdl = handler<F>;
  234|      2|    hdl::create(storage_, std::forward<Args>(args)...);
  235|      2|    handle_ = &hdl::handle;
  236|      2|    call_ = &hdl::call;
  237|      2|  }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E2_E6createIJSC_EEEvRNS0_7storageEDpOT_:
  118|      4|    static void create(storage& s, Args&&... args) {
  119|      4|      new (static_cast<void*>(&s.buf_)) T(std::forward<Args>(args)...);
  120|      4|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE12handler_baseINS8_13small_handlerIZNS4_C1EvEUlPT_E2_EEE6handleENS0_6actionEPNS0_7storageESI_:
  103|      2|    static void handle(action act, storage* current, storage* other = nullptr) {
  104|      2|      switch (act) {
  ------------------
  |  Branch (104:15): [True: 0, False: 2]
  ------------------
  105|      0|        case (action::destroy):
  ------------------
  |  Branch (105:9): [True: 0, False: 2]
  ------------------
  106|      0|          Derived::destroy(*current);
  107|      0|          break;
  108|      2|        case (action::move):
  ------------------
  |  Branch (108:9): [True: 2, False: 0]
  ------------------
  109|      2|          Derived::move(*current, *other);
  110|      2|          break;
  111|      2|      }
  112|      2|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E2_E7destroyERNS0_7storageE:
  122|      2|    static void destroy(storage& s) noexcept {
  123|      2|      T& value = *static_cast<T*>(static_cast<void*>(&s.buf_));
  124|      2|      value.~T();
  125|      2|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E2_E4moveERNS0_7storageESF_:
  127|      2|    static void move(storage& dst, storage& src) noexcept {
  128|      2|      create(dst, std::move(*static_cast<T*>(static_cast<void*>(&src.buf_))));
  129|      2|      destroy(src);
  130|      2|    }
_ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE13small_handlerIZNS4_C1EvEUlPT_E2_E4callERNS0_7storageES7_:
  132|  5.52k|    static R call(storage& s, ArgTypes... args) {
  133|  5.52k|      return std::invoke(*static_cast<T*>(static_cast<void*>(&s.buf_)),
  134|  5.52k|                         std::forward<ArgTypes>(args)...);
  135|  5.52k|    }
_ZN5ofats13any_invocableIFPvS1_NSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEbEEclES1_S6_b:
  345|  24.1k|    R operator()(ArgTypes... args) cv ref noexcept(noex) {                     \
  346|  24.1k|      return base_type::call(std::forward<ArgTypes>(args)...);                 \
  347|  24.1k|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE4callES2_S7_b:
  246|  24.1k|  R call(ArgTypes... args) noexcept(is_noexcept) {
  247|  24.1k|    return call_(storage_, std::forward<ArgTypes>(args)...);
  248|  24.1k|  }
_ZN5ofats13any_invocableIFPvS1_PN3uWS11HttpRequestEEEclES1_S4_:
  345|  10.0k|    R operator()(ArgTypes... args) cv ref noexcept(noex) {                     \
  346|  10.0k|      return base_type::call(std::forward<ArgTypes>(args)...);                 \
  347|  10.0k|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_PN3uWS11HttpRequestEEE4callES2_S5_:
  246|  10.0k|  R call(ArgTypes... args) noexcept(is_noexcept) {
  247|  10.0k|    return call_(storage_, std::forward<ArgTypes>(args)...);
  248|  10.0k|  }
Http.cpp:_ZN5ofats13any_invocableIFPvS1_PN3uWS11HttpRequestEEEC2IZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmEUlS1_S4_E_vEEOT_:
  303|  90.9k|    any_invocable(F&& f) {                                                     \
  304|  90.9k|      base_type::template create<std::decay_t<F>>(std::forward<F>(f));         \
  305|  90.9k|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_PN3uWS11HttpRequestEEEC2Ev:
  186|  90.9k|  any_invocable_impl() noexcept = default;
Http.cpp:_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_PN3uWS11HttpRequestEEE6createIZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmEUlS2_S5_E_JSB_EEEvDpOT0_:
  232|  90.9k|  void create(Args&&... args) {
  233|  90.9k|    using hdl = handler<F>;
  234|  90.9k|    hdl::create(storage_, std::forward<Args>(args)...);
  235|  90.9k|    handle_ = &hdl::handle;
  236|  90.9k|    call_ = &hdl::call;
  237|  90.9k|  }
Http.cpp:_ZN5ofats10any_detail14handler_traitsIPvJS2_PN3uWS11HttpRequestEEE13small_handlerIZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmEUlS2_S5_E_E6createIJSB_EEEvRNS0_7storageEDpOT_:
  118|  90.9k|    static void create(storage& s, Args&&... args) {
  119|  90.9k|      new (static_cast<void*>(&s.buf_)) T(std::forward<Args>(args)...);
  120|  90.9k|    }
Http.cpp:_ZN5ofats10any_detail14handler_traitsIPvJS2_PN3uWS11HttpRequestEEE12handler_baseINS6_13small_handlerIZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmEUlS2_S5_E_EEE6handleENS0_6actionEPNS0_7storageESH_:
  103|  90.9k|    static void handle(action act, storage* current, storage* other = nullptr) {
  104|  90.9k|      switch (act) {
  ------------------
  |  Branch (104:15): [True: 0, False: 90.9k]
  ------------------
  105|  90.9k|        case (action::destroy):
  ------------------
  |  Branch (105:9): [True: 90.9k, False: 0]
  ------------------
  106|  90.9k|          Derived::destroy(*current);
  107|  90.9k|          break;
  108|      0|        case (action::move):
  ------------------
  |  Branch (108:9): [True: 0, False: 90.9k]
  ------------------
  109|      0|          Derived::move(*current, *other);
  110|      0|          break;
  111|  90.9k|      }
  112|  90.9k|    }
Http.cpp:_ZN5ofats10any_detail14handler_traitsIPvJS2_PN3uWS11HttpRequestEEE13small_handlerIZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmEUlS2_S5_E_E7destroyERNS0_7storageE:
  122|  90.9k|    static void destroy(storage& s) noexcept {
  123|  90.9k|      T& value = *static_cast<T*>(static_cast<void*>(&s.buf_));
  124|  90.9k|      value.~T();
  125|  90.9k|    }
Http.cpp:_ZN5ofats10any_detail14handler_traitsIPvJS2_PN3uWS11HttpRequestEEE13small_handlerIZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmEUlS2_S5_E_E4callERNS0_7storageES2_S5_:
  132|  10.0k|    static R call(storage& s, ArgTypes... args) {
  133|  10.0k|      return std::invoke(*static_cast<T*>(static_cast<void*>(&s.buf_)),
  134|  10.0k|                         std::forward<ArgTypes>(args)...);
  135|  10.0k|    }
_ZN5ofats13any_invocableIFbPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEEclES6_:
  345|  9.45k|    R operator()(ArgTypes... args) cv ref noexcept(noex) {                     \
  346|  9.45k|      return base_type::call(std::forward<ArgTypes>(args)...);                 \
  347|  9.45k|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterIN10StaticData10RouterDataEEEEE4callES7_:
  246|  9.45k|  R call(ArgTypes... args) noexcept(is_noexcept) {
  247|  9.45k|    return call_(storage_, std::forward<ArgTypes>(args)...);
  248|  9.45k|  }
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_PN3uWS11HttpRequestEEED2Ev:
  206|  90.9k|  ~any_invocable_impl() { destroy(); }
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_PN3uWS11HttpRequestEEE7destroyEv:
  239|  90.9k|  void destroy() noexcept {
  240|  90.9k|    if (handle_) {
  ------------------
  |  Branch (240:9): [True: 90.9k, False: 0]
  ------------------
  241|  90.9k|      handle_(action::destroy, &storage_, nullptr);
  242|  90.9k|      handle_ = nullptr;
  243|  90.9k|    }
  244|  90.9k|  }
Http.cpp:_ZN5ofats13any_invocableIFPvS1_NSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEbEEC2IZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmEUlS1_S6_bE_vEEOT_:
  303|  90.9k|    any_invocable(F&& f) {                                                     \
  304|  90.9k|      base_type::template create<std::decay_t<F>>(std::forward<F>(f));         \
  305|  90.9k|    }                                                                          \
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEEC2Ev:
  186|  90.9k|  any_invocable_impl() noexcept = default;
Http.cpp:_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE6createIZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmEUlS2_S7_bE_JSD_EEEvDpOT0_:
  232|  90.9k|  void create(Args&&... args) {
  233|  90.9k|    using hdl = handler<F>;
  234|  90.9k|    hdl::create(storage_, std::forward<Args>(args)...);
  235|  90.9k|    handle_ = &hdl::handle;
  236|  90.9k|    call_ = &hdl::call;
  237|  90.9k|  }
Http.cpp:_ZN5ofats10any_detail14handler_traitsIPvJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE13small_handlerIZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmEUlS2_S7_bE_E6createIJSD_EEEvRNS0_7storageEDpOT_:
  118|  90.9k|    static void create(storage& s, Args&&... args) {
  119|  90.9k|      new (static_cast<void*>(&s.buf_)) T(std::forward<Args>(args)...);
  120|  90.9k|    }
Http.cpp:_ZN5ofats10any_detail14handler_traitsIPvJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE12handler_baseINS8_13small_handlerIZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmEUlS2_S7_bE_EEE6handleENS0_6actionEPNS0_7storageESJ_:
  103|  90.9k|    static void handle(action act, storage* current, storage* other = nullptr) {
  104|  90.9k|      switch (act) {
  ------------------
  |  Branch (104:15): [True: 0, False: 90.9k]
  ------------------
  105|  90.9k|        case (action::destroy):
  ------------------
  |  Branch (105:9): [True: 90.9k, False: 0]
  ------------------
  106|  90.9k|          Derived::destroy(*current);
  107|  90.9k|          break;
  108|      0|        case (action::move):
  ------------------
  |  Branch (108:9): [True: 0, False: 90.9k]
  ------------------
  109|      0|          Derived::move(*current, *other);
  110|      0|          break;
  111|  90.9k|      }
  112|  90.9k|    }
Http.cpp:_ZN5ofats10any_detail14handler_traitsIPvJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE13small_handlerIZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmEUlS2_S7_bE_E7destroyERNS0_7storageE:
  122|  90.9k|    static void destroy(storage& s) noexcept {
  123|  90.9k|      T& value = *static_cast<T*>(static_cast<void*>(&s.buf_));
  124|  90.9k|      value.~T();
  125|  90.9k|    }
Http.cpp:_ZN5ofats10any_detail14handler_traitsIPvJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE13small_handlerIZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmEUlS2_S7_bE_E4callERNS0_7storageES2_S7_b:
  132|  24.1k|    static R call(storage& s, ArgTypes... args) {
  133|  24.1k|      return std::invoke(*static_cast<T*>(static_cast<void*>(&s.buf_)),
  134|  24.1k|                         std::forward<ArgTypes>(args)...);
  135|  24.1k|    }
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEED2Ev:
  206|  90.9k|  ~any_invocable_impl() { destroy(); }
_ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE7destroyEv:
  239|  90.9k|  void destroy() noexcept {
  240|  90.9k|    if (handle_) {
  ------------------
  |  Branch (240:9): [True: 90.9k, False: 0]
  ------------------
  241|  90.9k|      handle_(action::destroy, &storage_, nullptr);
  242|  90.9k|      handle_ = nullptr;
  243|  90.9k|    }
  244|  90.9k|  }

Http.cpp:_ZN3uWSL20getDecodedQueryValueENSt3__117basic_string_viewIcNS0_11char_traitsIcEEEES4_:
   28|  20.1k|    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|  20.1k|        if (!key.length()) {
  ------------------
  |  Branch (31:13): [True: 10.0k, False: 10.0k]
  ------------------
   32|  10.0k|            return {};
   33|  10.0k|        }
   34|       |
   35|       |        /* Start with the whole querystring including initial '?' */
   36|  10.0k|        std::string_view queryString = rawQuery;
   37|       |
   38|       |        /* List of key, value could be cached for repeated fetches similar to how headers are, todo! */
   39|  12.1k|        while (queryString.length()) {
  ------------------
  |  Branch (39:16): [True: 3.99k, False: 8.15k]
  ------------------
   40|       |            /* Find boundaries of this statement */
   41|  3.99k|            std::string_view statement = queryString.substr(1, queryString.find('&', 1) - 1);
   42|       |
   43|       |            /* Only bother if first char of key match (early exit) */
   44|  3.99k|            if (statement.length() && statement[0] == key[0]) {
  ------------------
  |  Branch (44:17): [True: 2.90k, False: 1.08k]
  |  Branch (44:39): [True: 2.41k, False: 485]
  ------------------
   45|       |                /* Equal sign must be present and not in the end of statement */
   46|  2.41k|                auto equality = statement.find('=');
   47|  2.41k|                if (equality != std::string_view::npos) {
  ------------------
  |  Branch (47:21): [True: 1.82k, False: 593]
  ------------------
   48|       |
   49|  1.82k|                    std::string_view statementKey = statement.substr(0, equality);
   50|  1.82k|                    std::string_view statementValue = statement.substr(equality + 1);
   51|       |
   52|       |                    /* String comparison */
   53|  1.82k|                    if (key == statementKey) {
  ------------------
  |  Branch (53:25): [True: 1.34k, False: 481]
  ------------------
   54|       |
   55|       |                        /* Decode value inplace, put null at end if before length of original */
   56|  1.34k|                        char *in = (char *) statementValue.data();
   57|       |
   58|       |                        /* Write offset */
   59|  1.34k|                        unsigned int out = 0;
   60|       |
   61|       |                        /* Walk over all chars until end or null char, decoding in place */
   62|  37.0k|                        for (unsigned int i = 0; i < statementValue.length() && in[i]; i++) {
  ------------------
  |  Branch (62:50): [True: 35.8k, False: 1.14k]
  |  Branch (62:81): [True: 35.8k, False: 0]
  ------------------
   63|       |                                /* Only bother with '%' */
   64|  35.8k|                                if (in[i] == '%') {
  ------------------
  |  Branch (64:37): [True: 3.81k, False: 32.0k]
  ------------------
   65|       |                                    /* Do we have enough data for two bytes hex? */
   66|  3.81k|                                    if (i + 2 >= statementValue.length()) {
  ------------------
  |  Branch (66:41): [True: 204, False: 3.61k]
  ------------------
   67|    204|                                        return {};
   68|    204|                                    }
   69|       |
   70|       |                                    /* Two bytes hex */
   71|  3.61k|                                    int hex1 = in[i + 1] - '0';
   72|  3.61k|                                    if (hex1 > 9) {
  ------------------
  |  Branch (72:41): [True: 530, False: 3.08k]
  ------------------
   73|    530|                                        hex1 &= 223;
   74|    530|                                        hex1 -= 7;
   75|    530|                                    }
   76|       |
   77|  3.61k|                                    int hex2 = in[i + 2] - '0';
   78|  3.61k|                                    if (hex2 > 9) {
  ------------------
  |  Branch (78:41): [True: 600, False: 3.01k]
  ------------------
   79|    600|                                        hex2 &= 223;
   80|    600|                                        hex2 -= 7;
   81|    600|                                    }
   82|       |
   83|  3.61k|                                    *((unsigned char *) &in[out]) = (unsigned char) (hex1 * 16 + hex2);
   84|  3.61k|                                    i += 2;
   85|  32.0k|                                } else {
   86|       |                                    /* Is this even a rule? */
   87|  32.0k|                                    if (in[i] == '+') {
  ------------------
  |  Branch (87:41): [True: 692, False: 31.3k]
  ------------------
   88|    692|                                        in[out] = ' ';
   89|  31.3k|                                    } else {
   90|  31.3k|                                        in[out] = in[i];
   91|  31.3k|                                    }
   92|  32.0k|                                }
   93|       |
   94|       |                                /* We always only write one char */
   95|  35.6k|                                out++;
   96|  35.6k|                        }
   97|       |
   98|       |                        /* If decoded string is shorter than original, put null char to stop next read */
   99|  1.14k|                        if (out < statementValue.length()) {
  ------------------
  |  Branch (99:29): [True: 371, False: 770]
  ------------------
  100|    371|                            in[out] = 0;
  101|    371|                        }
  102|       |
  103|  1.14k|                        return statementValue.substr(0, out);
  104|  1.34k|                    }
  105|  1.82k|                } else {
  106|       |                    /* This querystring is invalid, cannot parse it */
  107|    593|                    return {nullptr, 0};
  108|    593|                }
  109|  2.41k|            }
  110|       |
  111|  2.05k|            queryString.remove_prefix(statement.length() + 1);
  112|  2.05k|        }
  113|       |
  114|       |        /* Nothing found is given as nullptr, while empty string is given as some pointer to the given buffer */
  115|  8.15k|        return {nullptr, 0};
  116|  10.0k|    }

LLVMFuzzerTestOneInput:
   76|  2.86k|extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
   77|       |    /* Create parser */
   78|  2.86k|    uWS::HttpParser httpParser;
   79|       |    /* User data */
   80|  2.86k|    void *user = (void *) 13;
   81|       |
   82|       |    /* If we are built with WITH_PROXY, pass a ProxyParser as reserved */
   83|  2.86k|    void *reserved = nullptr;
   84|       |#ifdef UWS_WITH_PROXY
   85|       |    uWS::ProxyParser pp;
   86|       |    reserved = (void *) &pp;
   87|       |#endif
   88|       |
   89|       |    /* Iterate the padded fuzz as chunks */
   90|  2.86k|    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|  2.86k|        if (size) {
   93|  2.86k|            size--;
   94|  2.86k|        } else {
   95|       |            /* We might be given zero length chunks */
   96|  2.86k|            return;
   97|  2.86k|        }
   98|       |
   99|       |        /* If user is null then ignore this chunk */
  100|  2.86k|        if (!user) {
  101|  2.86k|            return;
  102|  2.86k|        }
  103|       |
  104|       |        /* Parse it */
  105|  2.86k|        auto [err, returnedUser] = httpParser.consumePostPadded((char *) data, size, user, reserved, [reserved](void *s, uWS::HttpRequest *httpRequest) -> void * {
  106|       |
  107|  2.86k|            readBytes(httpRequest->getHeader(httpRequest->getUrl()));
  108|  2.86k|            readBytes(httpRequest->getMethod());
  109|  2.86k|            readBytes(httpRequest->getQuery());
  110|  2.86k|            readBytes(httpRequest->getQuery("hello"));
  111|  2.86k|            readBytes(httpRequest->getQuery(""));
  112|       |            //readBytes(httpRequest->getParameter(0));
  113|       |
  114|       |#ifdef UWS_WITH_PROXY
  115|       |            auto *pp = (uWS::ProxyParser *) reserved;
  116|       |            readBytes(pp->getSourceAddress());
  117|       |#endif
  118|       |
  119|       |            /* Route the method and URL in two passes */
  120|  2.86k|            staticData.router.getUserData() = {};
  121|  2.86k|            if (!staticData.router.route(httpRequest->getMethod(), httpRequest->getUrl())) {
  122|       |                /* It was not handled */
  123|  2.86k|                return nullptr;
  124|  2.86k|            }
  125|       |
  126|  2.86k|            for (auto p : *httpRequest) {
  127|       |
  128|  2.86k|            }
  129|       |
  130|       |            /* Return ok */
  131|  2.86k|            return s;
  132|       |
  133|  2.86k|        }, [](void *user, std::string_view data, bool fin) -> void * {
  134|       |
  135|       |            /* Return ok */
  136|  2.86k|            return user;
  137|       |
  138|  2.86k|        });
  139|       |
  140|  2.86k|        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|  2.86k|            user = nullptr;
  146|  2.86k|        }
  147|  2.86k|    });
  148|       |
  149|  2.86k|    return 0;
  150|  2.86k|}
_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|  2.72k|        router.add({"get"}, "/:hello/:hi", [](auto *h) mutable {
   27|  2.72k|            auto [paramsTop, params] = h->getParameters();
   28|       |
   29|       |            /* Something is horribly wrong */
   30|  2.72k|            if (paramsTop != 1 || !params[0].length() || !params[1].length()) {
  ------------------
  |  Branch (30:17): [True: 0, False: 2.72k]
  |  Branch (30:35): [True: 0, False: 2.72k]
  |  Branch (30:58): [True: 0, False: 2.72k]
  ------------------
   31|      0|                exit(-1);
   32|      0|            }
   33|       |
   34|       |            /* This route did handle it */
   35|  2.72k|            return true;
   36|  2.72k|        });
_ZZN10StaticDataC1EvENUlPT_E0_clIN3uWS10HttpRouterINS_10RouterDataEEEEEDaS1_:
   38|  1.09k|        router.add({"post"}, "/:hello/:hi/*", [](auto *h) mutable {
   39|  1.09k|            auto [paramsTop, params] = h->getParameters();
   40|       |
   41|       |            /* Something is horribly wrong */
   42|  1.09k|            if (paramsTop != 1 || !params[0].length() || !params[1].length()) {
  ------------------
  |  Branch (42:17): [True: 0, False: 1.09k]
  |  Branch (42:35): [True: 0, False: 1.09k]
  |  Branch (42:58): [True: 0, False: 1.09k]
  ------------------
   43|      0|                exit(-1);
   44|      0|            }
   45|       |
   46|       |            /* This route did handle it */
   47|  1.09k|            return true;
   48|  1.09k|        });
_ZZN10StaticDataC1EvENUlPT_E1_clIN3uWS10HttpRouterINS_10RouterDataEEEEEDaS1_:
   50|    108|        router.add({"get"}, "/*", [](auto *h) mutable {
   51|    108|            auto [paramsTop, params] = h->getParameters();
   52|       |
   53|       |            /* Something is horribly wrong */
   54|    108|            if (paramsTop != -1) {
  ------------------
  |  Branch (54:17): [True: 0, False: 108]
  ------------------
   55|      0|                exit(-1);
   56|      0|            }
   57|       |
   58|       |            /* This route did not handle it */
   59|    108|            return false;
   60|    108|        });
_ZZN10StaticDataC1EvENUlPT_E2_clIN3uWS10HttpRouterINS_10RouterDataEEEEEDaS1_:
   62|  5.52k|        router.add({"get"}, "/hi", [](auto *h) mutable {
   63|  5.52k|            auto [paramsTop, params] = h->getParameters();
   64|       |
   65|       |            /* Something is horribly wrong */
   66|  5.52k|            if (paramsTop != -1) {
  ------------------
  |  Branch (66:17): [True: 0, False: 5.52k]
  ------------------
   67|      0|                exit(-1);
   68|      0|            }
   69|       |
   70|       |            /* This route did handle it */
   71|  5.52k|            return true;
   72|  5.52k|        });
Http.cpp:_ZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhm:
   90|  91.9k|    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|  91.9k|        if (size) {
  ------------------
  |  Branch (92:13): [True: 91.9k, False: 23]
  ------------------
   93|  91.9k|            size--;
   94|  91.9k|        } else {
   95|       |            /* We might be given zero length chunks */
   96|     23|            return;
   97|     23|        }
   98|       |
   99|       |        /* If user is null then ignore this chunk */
  100|  91.9k|        if (!user) {
  ------------------
  |  Branch (100:13): [True: 1.05k, False: 90.9k]
  ------------------
  101|  1.05k|            return;
  102|  1.05k|        }
  103|       |
  104|       |        /* Parse it */
  105|  90.9k|        auto [err, returnedUser] = httpParser.consumePostPadded((char *) data, size, user, reserved, [reserved](void *s, uWS::HttpRequest *httpRequest) -> void * {
  106|       |
  107|  90.9k|            readBytes(httpRequest->getHeader(httpRequest->getUrl()));
  108|  90.9k|            readBytes(httpRequest->getMethod());
  109|  90.9k|            readBytes(httpRequest->getQuery());
  110|  90.9k|            readBytes(httpRequest->getQuery("hello"));
  111|  90.9k|            readBytes(httpRequest->getQuery(""));
  112|       |            //readBytes(httpRequest->getParameter(0));
  113|       |
  114|       |#ifdef UWS_WITH_PROXY
  115|       |            auto *pp = (uWS::ProxyParser *) reserved;
  116|       |            readBytes(pp->getSourceAddress());
  117|       |#endif
  118|       |
  119|       |            /* Route the method and URL in two passes */
  120|  90.9k|            staticData.router.getUserData() = {};
  121|  90.9k|            if (!staticData.router.route(httpRequest->getMethod(), httpRequest->getUrl())) {
  122|       |                /* It was not handled */
  123|  90.9k|                return nullptr;
  124|  90.9k|            }
  125|       |
  126|  90.9k|            for (auto p : *httpRequest) {
  127|       |
  128|  90.9k|            }
  129|       |
  130|       |            /* Return ok */
  131|  90.9k|            return s;
  132|       |
  133|  90.9k|        }, [](void *user, std::string_view data, bool fin) -> void * {
  134|       |
  135|       |            /* Return ok */
  136|  90.9k|            return user;
  137|       |
  138|  90.9k|        });
  139|       |
  140|  90.9k|        if (!returnedUser) {
  ------------------
  |  Branch (140:13): [True: 741, False: 90.1k]
  ------------------
  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|    741|            user = nullptr;
  146|    741|        }
  147|  90.9k|    });
Http.cpp:_ZZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmENKUlPvPN3uWS11HttpRequestEE_clES2_S5_:
  105|  10.0k|        auto [err, returnedUser] = httpParser.consumePostPadded((char *) data, size, user, reserved, [reserved](void *s, uWS::HttpRequest *httpRequest) -> void * {
  106|       |
  107|  10.0k|            readBytes(httpRequest->getHeader(httpRequest->getUrl()));
  108|  10.0k|            readBytes(httpRequest->getMethod());
  109|  10.0k|            readBytes(httpRequest->getQuery());
  110|  10.0k|            readBytes(httpRequest->getQuery("hello"));
  111|  10.0k|            readBytes(httpRequest->getQuery(""));
  112|       |            //readBytes(httpRequest->getParameter(0));
  113|       |
  114|       |#ifdef UWS_WITH_PROXY
  115|       |            auto *pp = (uWS::ProxyParser *) reserved;
  116|       |            readBytes(pp->getSourceAddress());
  117|       |#endif
  118|       |
  119|       |            /* Route the method and URL in two passes */
  120|  10.0k|            staticData.router.getUserData() = {};
  121|  10.0k|            if (!staticData.router.route(httpRequest->getMethod(), httpRequest->getUrl())) {
  ------------------
  |  Branch (121:17): [True: 741, False: 9.34k]
  ------------------
  122|       |                /* It was not handled */
  123|    741|                return nullptr;
  124|    741|            }
  125|       |
  126|  17.7k|            for (auto p : *httpRequest) {
  ------------------
  |  Branch (126:25): [True: 17.7k, False: 9.34k]
  ------------------
  127|       |
  128|  17.7k|            }
  129|       |
  130|       |            /* Return ok */
  131|  9.34k|            return s;
  132|       |
  133|  10.0k|        }, [](void *user, std::string_view data, bool fin) -> void * {
Http.cpp:_ZZZ22LLVMFuzzerTestOneInputENK3$_0clEPKhmENKUlPvNSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbE_clES2_S7_b:
  133|  24.1k|        }, [](void *user, std::string_view data, bool fin) -> void * {
  134|       |
  135|       |            /* Return ok */
  136|  24.1k|            return user;
  137|       |
  138|  24.1k|        });

Http.cpp:_ZL11makeChunkedPKhmNSt3__18functionIFvS0_mEEE:
   28|  2.86k|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|  94.8k|    for (int i = 0; i < size; ) {
  ------------------
  |  Branch (30:21): [True: 91.9k, False: 2.86k]
  ------------------
   31|  91.9k|        unsigned int chunkSize = data[i++];
   32|  91.9k|        if (!chunkSize) {
  ------------------
  |  Branch (32:13): [True: 1.25k, False: 90.7k]
  ------------------
   33|  1.25k|            chunkSize = size - i;
   34|  90.7k|        } else {
   35|  90.7k|            chunkSize = std::min<int>(chunkSize, size - i);
   36|  90.7k|        }
   37|       |
   38|  91.9k|        cb(data + i, chunkSize);
   39|  91.9k|        i += chunkSize;
   40|  91.9k|    }
   41|  2.86k|}
Http.cpp:_ZL10makePaddedPKhm:
   11|  2.86k|static inline const uint8_t *makePadded(const uint8_t *data, size_t size) {
   12|  2.86k|    static int paddedLength = 512 * 1024;
   13|  2.86k|    static char *padded = new char[128 + paddedLength + 128];
   14|       |
   15|       |    /* Increase landing area if required */
   16|  2.86k|    if (paddedLength < size) {
  ------------------
  |  Branch (16:9): [True: 16, False: 2.84k]
  ------------------
   17|     16|        delete [] padded;
   18|     16|        paddedLength = size;
   19|     16|        padded = new char [128 + paddedLength + 128];
   20|     16|    }
   21|       |
   22|  2.86k|    memcpy(padded + 128, data, size);
   23|       |
   24|  2.86k|    return (uint8_t *) padded + 128;
   25|  2.86k|}
Http.cpp:_ZL9readBytesNSt3__117basic_string_viewIcNS_11char_traitsIcEEEE:
   44|  50.4k|static inline void readBytes(std::string_view s) {
   45|  50.4k|    volatile int sum = 0;
   46|   211k|    for (int i = 0; i < s.size(); i++) {
  ------------------
  |  Branch (46:21): [True: 161k, False: 50.4k]
  ------------------
   47|   161k|        sum += s[i];
   48|   161k|    }
   49|  50.4k|}

