Extensions.cpp:_ZN3uWSL20negotiateCompressionEbiiNSt3__117basic_string_viewIcNS0_11char_traitsIcEEEE:
  144|  1.99k|static inline std::tuple<bool, int, int, std::string_view> negotiateCompression(bool wantCompression, int wantedCompressionWindow, int wantedInflationWindow, std::string_view offer) {
  145|       |
  146|       |    /* If we don't want compression then we are done here */
  147|  1.99k|    if (!wantCompression) {
  ------------------
  |  Branch (147:9): [True: 664, False: 1.32k]
  ------------------
  148|    664|        return {false, 0, 0, ""};
  149|    664|    }
  150|       |
  151|  1.32k|    ExtensionsParser ep(offer.data(), offer.length());
  152|       |
  153|  1.32k|    static thread_local std::string response;
  154|  1.32k|    response = "";
  155|       |
  156|  1.32k|    int compressionWindow = wantedCompressionWindow;
  157|  1.32k|    int inflationWindow = wantedInflationWindow;
  158|  1.32k|    bool compression = false;
  159|       |
  160|  1.32k|    if (ep.xWebKitDeflateFrame) {
  ------------------
  |  Branch (160:9): [True: 68, False: 1.26k]
  ------------------
  161|       |        /* We now have compression */
  162|     68|        compression = true;
  163|     68|        response = "x-webkit-deflate-frame";
  164|       |
  165|       |        /* If the other peer has DEMANDED us no sliding window,
  166|       |         * we cannot compress with anything other than shared compressor */
  167|     68|        if (ep.noContextTakeover) {
  ------------------
  |  Branch (167:13): [True: 2, False: 66]
  ------------------
  168|       |            /* We must fail here right now (fix pub/sub) */
  169|      2|#ifndef UWS_ALLOW_SHARED_AND_DEDICATED_COMPRESSOR_MIX
  170|      2|            if (wantedCompressionWindow != 0) {
  ------------------
  |  Branch (170:17): [True: 1, False: 1]
  ------------------
  171|      1|                return {false, 0, 0, ""};
  172|      1|            }
  173|      1|#endif
  174|       |
  175|      1|            compressionWindow = 0;
  176|      1|        }
  177|       |
  178|       |        /* If the other peer has DEMANDED us to use a limited sliding window,
  179|       |         * we have to limit out compression sliding window */
  180|     67|        if (ep.maxWindowBits && ep.maxWindowBits < compressionWindow) {
  ------------------
  |  Branch (180:13): [True: 64, False: 3]
  |  Branch (180:33): [True: 8, False: 56]
  ------------------
  181|      8|            compressionWindow = ep.maxWindowBits;
  182|      8|#ifndef UWS_ALLOW_8_WINDOW_BITS
  183|       |            /* We cannot really deny this, so we have to disable compression in this case */
  184|      8|            if (compressionWindow == 8) {
  ------------------
  |  Branch (184:17): [True: 1, False: 7]
  ------------------
  185|      1|                return {false, 0, 0, ""};
  186|      1|            }
  187|      8|#endif
  188|      8|        }
  189|       |
  190|       |        /* We decide our own inflation sliding window (and their compression sliding window) */
  191|     66|        if (wantedInflationWindow < 15) {
  ------------------
  |  Branch (191:13): [True: 66, False: 0]
  ------------------
  192|     66|            if (!wantedInflationWindow) {
  ------------------
  |  Branch (192:17): [True: 66, False: 0]
  ------------------
  193|     66|                response += "; no_context_takeover";
  194|     66|            } else {
  195|      0|                response += "; max_window_bits=" + std::to_string(wantedInflationWindow);
  196|      0|            }
  197|     66|        }
  198|  1.26k|    } else if (ep.perMessageDeflate) {
  ------------------
  |  Branch (198:16): [True: 130, False: 1.13k]
  ------------------
  199|       |        /* We now have compression */
  200|    130|        compression = true;
  201|    130|        response = "permessage-deflate";
  202|       |
  203|    130|        if (ep.clientNoContextTakeover) {
  ------------------
  |  Branch (203:13): [True: 2, False: 128]
  ------------------
  204|      2|            inflationWindow = 0;
  205|    128|        } else if (ep.clientMaxWindowBits && ep.clientMaxWindowBits != 1) {
  ------------------
  |  Branch (205:20): [True: 64, False: 64]
  |  Branch (205:46): [True: 62, False: 2]
  ------------------
  206|     62|            inflationWindow = std::min<int>(ep.clientMaxWindowBits, inflationWindow);
  207|     62|        }
  208|       |
  209|       |        /* Whatever we have now, write */
  210|    130|        if (inflationWindow < 15) {
  ------------------
  |  Branch (210:13): [True: 130, False: 0]
  ------------------
  211|    130|            if (!inflationWindow || !ep.clientMaxWindowBits) {
  ------------------
  |  Branch (211:17): [True: 130, False: 0]
  |  Branch (211:37): [True: 0, False: 0]
  ------------------
  212|    130|                response += "; client_no_context_takeover";
  213|    130|                inflationWindow = 0;
  214|    130|            } else {
  215|      0|                response += "; client_max_window_bits=" + std::to_string(inflationWindow);
  216|      0|            }
  217|    130|        }
  218|       |
  219|       |        /* This block basically lets the client lower it */
  220|    130|        if (ep.serverNoContextTakeover) {
  ------------------
  |  Branch (220:13): [True: 2, False: 128]
  ------------------
  221|       |        /* This is an important (temporary) fix since we haven't allowed
  222|       |         * these two modes to mix, and pub/sub will not handle this case (yet) */
  223|       |#ifdef UWS_ALLOW_SHARED_AND_DEDICATED_COMPRESSOR_MIX
  224|       |            compressionWindow = 0;
  225|       |#endif
  226|    128|        } else if (ep.serverMaxWindowBits) {
  ------------------
  |  Branch (226:20): [True: 60, False: 68]
  ------------------
  227|     60|            compressionWindow = std::min<int>(ep.serverMaxWindowBits, compressionWindow);
  228|     60|#ifndef UWS_ALLOW_8_WINDOW_BITS
  229|       |            /* Zlib cannot do windowBits=8, memLevel=1 so we raise it up to 9 minimum */
  230|     60|            if (compressionWindow == 8) {
  ------------------
  |  Branch (230:17): [True: 1, False: 59]
  ------------------
  231|      1|                compressionWindow = 9;
  232|      1|            }
  233|     60|#endif
  234|     60|        }
  235|       |
  236|       |        /* Whatever we have now, write */
  237|    130|        if (compressionWindow < 15) {
  ------------------
  |  Branch (237:13): [True: 130, False: 0]
  ------------------
  238|    130|            if (!compressionWindow) {
  ------------------
  |  Branch (238:17): [True: 65, False: 65]
  ------------------
  239|     65|                response += "; server_no_context_takeover";
  240|     65|            } else {
  241|     65|                response += "; server_max_window_bits=" + std::to_string(compressionWindow);
  242|     65|            }
  243|    130|        }
  244|    130|    }
  245|       |
  246|       |    /* A final sanity check (this check does not actually catch too high values!) */
  247|  1.32k|    if ((compressionWindow && compressionWindow < 8) || compressionWindow > 15 || (inflationWindow && inflationWindow < 8) || inflationWindow > 15) {
  ------------------
  |  Branch (247:10): [True: 662, False: 664]
  |  Branch (247:31): [True: 8, False: 654]
  |  Branch (247:57): [True: 0, False: 1.31k]
  |  Branch (247:84): [True: 0, False: 1.31k]
  |  Branch (247:103): [True: 0, False: 0]
  |  Branch (247:127): [True: 0, False: 1.31k]
  ------------------
  248|      8|        return {false, 0, 0, ""};
  249|      8|    }
  250|       |
  251|  1.31k|    return {compression, compressionWindow, inflationWindow, response};
  252|  1.32k|}
_ZN3uWS16ExtensionsParserC2EPKcm:
   93|  1.32k|    ExtensionsParser(const char *data, size_t length) {
   94|  1.32k|        const char *stop = data + length;
   95|  1.32k|        int token = 1;
   96|       |
   97|       |        /* Ignore anything before permessage-deflate or x-webkit-deflate-frame */
   98|  3.42k|        for (; token && token != TOK_PERMESSAGE_DEFLATE && token != TOK_X_WEBKIT_DEFLATE_FRAME; token = getToken(data, stop));
  ------------------
  |  Branch (98:16): [True: 2.29k, False: 1.13k]
  |  Branch (98:25): [True: 2.16k, False: 130]
  |  Branch (98:60): [True: 2.09k, False: 68]
  ------------------
   99|       |
  100|       |        /* What protocol are we going to use? */
  101|  1.32k|        perMessageDeflate = (token == TOK_PERMESSAGE_DEFLATE);
  102|  1.32k|        xWebKitDeflateFrame = (token == TOK_X_WEBKIT_DEFLATE_FRAME);
  103|       |
  104|  4.18k|        while ((token = getToken(data, stop))) {
  ------------------
  |  Branch (104:16): [True: 2.85k, False: 1.32k]
  ------------------
  105|  2.85k|            switch (token) {
  106|      2|            case TOK_X_WEBKIT_DEFLATE_FRAME:
  ------------------
  |  Branch (106:13): [True: 2, False: 2.85k]
  ------------------
  107|       |                /* Duplicates not allowed/supported */
  108|      2|                return;
  109|    192|            case TOK_NO_CONTEXT_TAKEOVER:
  ------------------
  |  Branch (109:13): [True: 192, False: 2.66k]
  ------------------
  110|    192|                noContextTakeover = true;
  111|    192|                break;
  112|    260|            case TOK_MAX_WINDOW_BITS:
  ------------------
  |  Branch (112:13): [True: 260, False: 2.59k]
  ------------------
  113|    260|                maxWindowBits = 1;
  114|    260|                lastInteger = &maxWindowBits;
  115|    260|                break;
  116|      2|            case TOK_PERMESSAGE_DEFLATE:
  ------------------
  |  Branch (116:13): [True: 2, False: 2.85k]
  ------------------
  117|       |                /* Duplicates not allowed/supported */
  118|      2|                return;
  119|    192|            case TOK_SERVER_NO_CONTEXT_TAKEOVER:
  ------------------
  |  Branch (119:13): [True: 192, False: 2.66k]
  ------------------
  120|    192|                serverNoContextTakeover = true;
  121|    192|                break;
  122|    192|            case TOK_CLIENT_NO_CONTEXT_TAKEOVER:
  ------------------
  |  Branch (122:13): [True: 192, False: 2.66k]
  ------------------
  123|    192|                clientNoContextTakeover = true;
  124|    192|                break;
  125|    252|            case TOK_SERVER_MAX_WINDOW_BITS:
  ------------------
  |  Branch (125:13): [True: 252, False: 2.60k]
  ------------------
  126|    252|                serverMaxWindowBits = 1;
  127|    252|                lastInteger = &serverMaxWindowBits;
  128|    252|                break;
  129|    258|            case TOK_CLIENT_MAX_WINDOW_BITS:
  ------------------
  |  Branch (129:13): [True: 258, False: 2.59k]
  ------------------
  130|    258|                clientMaxWindowBits = 1;
  131|    258|                lastInteger = &clientMaxWindowBits;
  132|    258|                break;
  133|  1.50k|            default:
  ------------------
  |  Branch (133:13): [True: 1.50k, False: 1.35k]
  ------------------
  134|  1.50k|                if (token < 0 && lastInteger) {
  ------------------
  |  Branch (134:21): [True: 830, False: 676]
  |  Branch (134:34): [True: 372, False: 458]
  ------------------
  135|    372|                    *lastInteger = -token;
  136|    372|                }
  137|  1.50k|                break;
  138|  2.85k|            }
  139|  2.85k|        }
  140|  1.32k|    }
_ZN3uWS16ExtensionsParser8getTokenERPKcS2_:
   69|  6.27k|    int getToken(const char *&in, const char *stop) {
   70|  9.97k|        while (in != stop && !isalnum(*in)) {
  ------------------
  |  Branch (70:16): [True: 8.23k, False: 1.74k]
  |  Branch (70:30): [True: 3.69k, False: 4.53k]
  ------------------
   71|  3.69k|            in++;
   72|  3.69k|        }
   73|       |
   74|       |        /* Don't care more than this for now */
   75|  6.27k|        static_assert(SHRT_MIN > INT_MIN, "Integer overflow fix is invalid for this platform, report this as a bug!");
   76|       |
   77|  6.27k|        int hashedToken = 0;
   78|  4.31M|        while (in != stop && (isalnum(*in) || *in == '-' || *in == '_')) {
  ------------------
  |  Branch (78:16): [True: 4.31M, False: 2.97k]
  |  Branch (78:31): [True: 4.30M, False: 4.56k]
  |  Branch (78:47): [True: 768, False: 3.79k]
  |  Branch (78:61): [True: 492, False: 3.30k]
  ------------------
   79|  4.31M|            if (isdigit(*in)) {
  ------------------
  |  Branch (79:17): [True: 6.94k, False: 4.30M]
  ------------------
   80|       |                /* This check is a quick and incorrect fix for integer overflow
   81|       |                 * in oss-fuzz but we don't care as it doesn't matter either way */
   82|  6.94k|                if (hashedToken > SHRT_MIN && hashedToken < SHRT_MAX) {
  ------------------
  |  Branch (82:21): [True: 6.47k, False: 470]
  |  Branch (82:47): [True: 5.96k, False: 510]
  ------------------
   83|  5.96k|                    hashedToken = hashedToken * 10 - (*in - '0');
   84|  5.96k|                }
   85|  4.30M|            } else {
   86|  4.30M|                hashedToken += *in;
   87|  4.30M|            }
   88|  4.31M|            in++;
   89|  4.31M|        }
   90|  6.27k|        return hashedToken;
   91|  6.27k|    }

LLVMFuzzerTestOneInput:
   12|    664|extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
   13|       |
   14|       |    /* This one must not return shared compressor, or above 13 */
   15|    664|    {
   16|    664|        auto [negCompression, negCompressionWindow, negInflationWindow, response] = uWS::negotiateCompression(true, 13, 0, std::string_view((char *) data, size));
   17|       |
   18|    664|        if (negCompression) {
  ------------------
  |  Branch (18:13): [True: 89, False: 575]
  ------------------
   19|       |            /* If we want dedicated compression, we must not end up here! */
   20|     89|            free((void *) (negCompressionWindow == 0));
   21|       |
   22|       |            /* Some more checks (freeing 0 does nothing) */
   23|     89|            free((void *) (negCompressionWindow > 13));
   24|     89|            free((void *) (negInflationWindow != 0));
   25|     89|            free((void *) (negInflationWindow < 0 || negInflationWindow > 15 || negCompressionWindow < 0 || negCompressionWindow > 15));
  ------------------
  |  Branch (25:28): [True: 0, False: 89]
  |  Branch (25:54): [True: 0, False: 89]
  |  Branch (25:81): [True: 0, False: 89]
  |  Branch (25:109): [True: 0, False: 89]
  ------------------
   26|     89|        }
   27|    664|    }
   28|       |
   29|       |    /* This one must not return anything over 0 (only shared) */
   30|    664|    {
   31|    664|        auto [negCompression, negCompressionWindow, negInflationWindow, response] = uWS::negotiateCompression(true, 0, 0, std::string_view((char *) data, size));
   32|       |
   33|    664|        if (negCompression) {
  ------------------
  |  Branch (33:13): [True: 99, False: 565]
  ------------------
   34|       |            /* If we want shared compression, we must not end up here! */
   35|     99|            free((void *) (negCompressionWindow != 0));
   36|     99|        }
   37|    664|    }
   38|       |
   39|       |
   40|       |    /* Whatever, this one must not negotiate anything */
   41|    664|    {
   42|    664|        auto [negCompression, negCompressionWindow, negInflationWindow, response] = uWS::negotiateCompression(false, 13, 15, std::string_view((char *) data, size));
   43|       |
   44|    664|        if (negCompression) {
  ------------------
  |  Branch (44:13): [True: 0, False: 664]
  ------------------
   45|      0|            free((void *) -1);
   46|      0|        }
   47|    664|    }
   48|       |
   49|    664|    return 0;
   50|    664|}

