LLVMFuzzerTestOneInput:
   11|  1.42k|extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
   12|       |
   13|  1.42k|    if (!size) {
  ------------------
  |  Branch (13:9): [True: 0, False: 1.42k]
  ------------------
   14|      0|        return 0;
   15|      0|    }
   16|       |
   17|  1.42k|    char *mutableMemory = (char *) malloc(size);
   18|  1.42k|    memcpy(mutableMemory, data, size);
   19|       |
   20|       |    /* First byte determines how long contentType is */
   21|  1.42k|    unsigned char contentTypeLength = data[0];
   22|  1.42k|    size--;
   23|       |
   24|  1.42k|    std::string_view contentType((char *) mutableMemory + 1, std::min<size_t>(contentTypeLength, size));
   25|  1.42k|    size -= contentType.length();
   26|       |
   27|  1.42k|    std::string_view body((char *) mutableMemory + 1 + contentType.length(), size);
   28|       |
   29|  1.42k|    uWS::MultipartParser mp(contentType);
   30|  1.42k|    if (mp.isValid()) {
  ------------------
  |  Branch (30:9): [True: 1.27k, False: 152]
  ------------------
   31|  1.27k|        mp.setBody(body);
   32|       |
   33|  1.27k|        std::pair<std::string_view, std::string_view> headers[10];
   34|       |
   35|  4.20k|        while (true) {
  ------------------
  |  Branch (35:16): [Folded - Ignored]
  ------------------
   36|  4.20k|            std::optional<std::string_view> optionalPart = mp.getNextPart(headers);
   37|  4.20k|            if (!optionalPart.has_value()) {
  ------------------
  |  Branch (37:17): [True: 1.27k, False: 2.93k]
  ------------------
   38|  1.27k|                break;
   39|  1.27k|            }
   40|       |
   41|  2.93k|            std::string_view part = optionalPart.value();
   42|       |
   43|  9.91k|            for (int i = 0; headers[i].first.length(); i++) {
  ------------------
  |  Branch (43:29): [True: 6.98k, False: 2.93k]
  ------------------
   44|       |                /* We care about content-type and content-disposition */
   45|  6.98k|                if (headers[i].first == "content-disposition") {
  ------------------
  |  Branch (45:21): [True: 5.16k, False: 1.82k]
  ------------------
   46|       |                    /* Parse the parameters */
   47|  5.16k|                    uWS::ParameterParser pp(headers[i].second);
   48|   170k|                    while (true) {
  ------------------
  |  Branch (48:28): [Folded - Ignored]
  ------------------
   49|   170k|                        auto [key, value] = pp.getKeyValue();
   50|   170k|                        if (!key.length()) {
  ------------------
  |  Branch (50:29): [True: 5.16k, False: 165k]
  ------------------
   51|  5.16k|                            break;
   52|  5.16k|                        }
   53|   170k|                    }
   54|  5.16k|                }
   55|  6.98k|            }
   56|  2.93k|        }
   57|  1.27k|    }
   58|       |
   59|  1.42k|    free(mutableMemory);
   60|  1.42k|    return 0;
   61|  1.42k|}

MultipartParser.cpp:_ZN3uWSL10getHeadersEPcS0_PNSt3__14pairINS1_17basic_string_viewIcNS1_11char_traitsIcEEEES6_EE:
   33|  3.06k|    static inline unsigned int getHeaders(char *postPaddedBuffer, char *end, std::pair<std::string_view, std::string_view> *headers) {
   34|  3.06k|        char *preliminaryKey, *preliminaryValue, *start = postPaddedBuffer;
   35|       |
   36|  10.6k|        for (unsigned int i = 0; i < MAX_HEADERS; i++) {
  ------------------
  |  |   28|  10.6k|#define MAX_HEADERS 10
  ------------------
  |  Branch (36:34): [True: 10.6k, False: 5]
  ------------------
   37|  4.21M|            for (preliminaryKey = postPaddedBuffer; (*postPaddedBuffer != ':') & (*(unsigned char *)postPaddedBuffer > 32); *(postPaddedBuffer++) |= 32);
  ------------------
  |  Branch (37:53): [True: 4.20M, False: 10.6k]
  ------------------
   38|  10.6k|            if (*postPaddedBuffer == '\r') {
  ------------------
  |  Branch (38:17): [True: 2.99k, False: 7.64k]
  ------------------
   39|  2.99k|                if ((postPaddedBuffer != end) & (postPaddedBuffer[1] == '\n') /* & (i > 0) */) { // multipart does not require any headers like http does
  ------------------
  |  Branch (39:21): [True: 2.93k, False: 58]
  ------------------
   40|  2.93k|                    headers->first = std::string_view(nullptr, 0);
   41|  2.93k|                    return (unsigned int) ((postPaddedBuffer + 2) - start);
   42|  2.93k|                } else {
   43|     58|                    return 0;
   44|     58|                }
   45|  7.64k|            } else {
   46|  7.64k|                headers->first = std::string_view(preliminaryKey, (size_t) (postPaddedBuffer - preliminaryKey));
   47|  9.67k|                for (postPaddedBuffer++; (*postPaddedBuffer == ':' || *(unsigned char *)postPaddedBuffer < 33) && *postPaddedBuffer != '\r'; postPaddedBuffer++);
  ------------------
  |  Branch (47:43): [True: 15, False: 9.65k]
  |  Branch (47:71): [True: 3.70k, False: 5.94k]
  |  Branch (47:115): [True: 2.02k, False: 1.70k]
  ------------------
   48|  7.64k|                preliminaryValue = postPaddedBuffer;
   49|  7.64k|                postPaddedBuffer = (char *) memchr(postPaddedBuffer, '\r', end - postPaddedBuffer);
   50|  7.64k|                if (postPaddedBuffer && postPaddedBuffer[1] == '\n') {
  ------------------
  |  Branch (50:21): [True: 7.58k, False: 59]
  |  Branch (50:41): [True: 7.57k, False: 12]
  ------------------
   51|  7.57k|                    headers->second = std::string_view(preliminaryValue, (size_t) (postPaddedBuffer - preliminaryValue));
   52|  7.57k|                    postPaddedBuffer += 2;
   53|  7.57k|                    headers++;
   54|  7.57k|                } else {
   55|     71|                    return 0;
   56|     71|                }
   57|  7.64k|            }
   58|  10.6k|        }
   59|      5|        return 0;
   60|  3.06k|    }

_ZN3uWS15MultipartParserC2ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
  134|  1.42k|        MultipartParser(std::string_view contentType) {
  135|       |
  136|       |            /* We expect the form "multipart/something;somethingboundary=something" */
  137|  1.42k|            if (contentType.length() < 10 || contentType.substr(0, 10) != "multipart/") {
  ------------------
  |  Branch (137:17): [True: 38, False: 1.38k]
  |  Branch (137:46): [True: 92, False: 1.29k]
  ------------------
  138|    130|                return;
  139|    130|            }
  140|       |
  141|       |            /* For now we simply guess boundary will lie between = and end. This is not entirely
  142|       |            * standards compliant as boundary may be expressed with or without " and spaces */
  143|  1.29k|            auto equalToken = contentType.find('=', 10);
  144|  1.29k|            if (equalToken != std::string_view::npos) {
  ------------------
  |  Branch (144:17): [True: 1.28k, False: 5]
  ------------------
  145|       |
  146|       |                /* Boundary must be less than or equal to 70 chars yet 1 char or longer */
  147|  1.28k|                std::string_view boundary = contentType.substr(equalToken + 1);
  148|  1.28k|                if (!boundary.length() || boundary.length() > 70) {
  ------------------
  |  Branch (148:21): [True: 7, False: 1.28k]
  |  Branch (148:43): [True: 10, False: 1.27k]
  ------------------
  149|       |                    /* Invalid size */
  150|     17|                    return;
  151|     17|                }
  152|       |
  153|       |                /* Prepend it with two hyphens */
  154|  1.27k|                prependedBoundaryBuffer[0] = prependedBoundaryBuffer[1] = '-';
  155|  1.27k|                memcpy(&prependedBoundaryBuffer[2], boundary.data(), boundary.length());
  156|       |
  157|  1.27k|                prependedBoundary = {prependedBoundaryBuffer, boundary.length() + 2};
  158|  1.27k|            }
  159|  1.29k|        }
_ZN3uWS15MultipartParser7isValidEv:
  162|  1.42k|        bool isValid() {
  163|  1.42k|            return prependedBoundary.length() != 0;
  164|  1.42k|        }
_ZN3uWS15MultipartParser7setBodyENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
  167|  1.27k|        void setBody(std::string_view body) {
  168|  1.27k|            remainingBody = body;
  169|  1.27k|        }
_ZN3uWS15MultipartParser11getNextPartEPNSt3__14pairINS1_17basic_string_viewIcNS1_11char_traitsIcEEEES6_EE:
  172|  4.20k|        std::optional<std::string_view> getNextPart(std::pair<std::string_view, std::string_view> *headers) {
  173|       |
  174|       |            /* The remaining two hyphens should be shorter than the boundary */
  175|  4.20k|            if (remainingBody.length() < prependedBoundary.length()) {
  ------------------
  |  Branch (175:17): [True: 921, False: 3.28k]
  ------------------
  176|       |                /* We are done now */
  177|    921|                return std::nullopt;
  178|    921|            }
  179|       |
  180|  3.28k|            if (first) {
  ------------------
  |  Branch (180:17): [True: 1.24k, False: 2.04k]
  ------------------
  181|  1.24k|                auto nextBoundary = remainingBody.find(prependedBoundary);
  182|  1.24k|                if (nextBoundary == std::string_view::npos) {
  ------------------
  |  Branch (182:21): [True: 97, False: 1.14k]
  ------------------
  183|       |                    /* Cannot parse */
  184|     97|                    return std::nullopt;
  185|     97|                }
  186|       |
  187|       |                /* Toss away boundary and anything before it */
  188|  1.14k|                remainingBody.remove_prefix(nextBoundary + prependedBoundary.length());
  189|  1.14k|                first = false;
  190|  1.14k|            }
  191|       |
  192|  3.18k|            auto nextEndBoundary = remainingBody.find(prependedBoundary);
  193|  3.18k|            if (nextEndBoundary == std::string_view::npos) {
  ------------------
  |  Branch (193:17): [True: 86, False: 3.10k]
  ------------------
  194|       |                /* Cannot parse (or simply done) */
  195|     86|                return std::nullopt;
  196|     86|            }
  197|       |
  198|  3.10k|            std::string_view part = remainingBody.substr(0, nextEndBoundary);
  199|  3.10k|            remainingBody.remove_prefix(nextEndBoundary + prependedBoundary.length());
  200|       |
  201|       |            /* Also strip rn before and rn after the part */
  202|  3.10k|            if (part.length() < 4) {
  ------------------
  |  Branch (202:17): [True: 32, False: 3.06k]
  ------------------
  203|       |                /* Cannot strip */
  204|     32|                return std::nullopt;
  205|     32|            }
  206|  3.06k|            part.remove_prefix(2);
  207|  3.06k|            part.remove_suffix(2);
  208|       |
  209|       |            /* We are allowed to post pad like this because we know the boundary is at least 2 bytes */
  210|       |            /* This makes parsing a second pass invalid, so you can only iterate over parts once */
  211|  3.06k|            memset((char *) part.data() + part.length(), '\r', 1);
  212|       |
  213|       |            /* For this to be a valid part, we need to consume at least 4 bytes (\r\n\r\n) */
  214|  3.06k|            int consumed = getHeaders((char *) part.data(), (char *) part.data() + part.length(), headers);
  215|       |
  216|  3.06k|            if (!consumed) {
  ------------------
  |  Branch (216:17): [True: 134, False: 2.93k]
  ------------------
  217|       |                /* This is an invalid part */
  218|    134|                return std::nullopt;
  219|    134|            }
  220|       |
  221|       |            /* Strip away the headers from the part body data */
  222|  2.93k|            part.remove_prefix(consumed);
  223|       |
  224|       |            /* Now pass whatever is remaining of the part */
  225|  2.93k|            return part;
  226|  3.06k|        }
_ZN3uWS15ParameterParserC2ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
   38|  5.16k|        ParameterParser(std::string_view line) {
   39|  5.16k|            remainingLine = line;
   40|  5.16k|        }
_ZN3uWS15ParameterParser11getKeyValueEv:
   44|   170k|        std::pair<std::string_view, std::string_view> getKeyValue() {
   45|   170k|            auto key = getToken();
   46|   170k|            auto op = getToken();
   47|       |
   48|   170k|            if (!op.length()) {
  ------------------
  |  Branch (48:17): [True: 7.34k, False: 163k]
  ------------------
   49|  7.34k|                return {key, ""};
   50|  7.34k|            }
   51|       |
   52|   163k|            if (op[0] != ';') {
  ------------------
  |  Branch (52:17): [True: 156k, False: 6.93k]
  ------------------
   53|   156k|                auto value = getToken();
   54|       |                /* Strip ; or if at end, nothing */
   55|   156k|                getToken();
   56|   156k|                return {key, value};
   57|   156k|            }
   58|       |
   59|  6.93k|            return {key, ""};
   60|   163k|        }
_ZN3uWS15ParameterParser8getTokenEv:
   66|   653k|        std::string_view getToken() {
   67|       |            /* Strip whitespace */
   68|  1.70M|            while (remainingLine.length() && isspace(remainingLine[0])) {
  ------------------
  |  Branch (68:20): [True: 1.69M, False: 12.2k]
  |  Branch (68:46): [True: 1.05M, False: 640k]
  ------------------
   69|  1.05M|                remainingLine.remove_prefix(1);
   70|  1.05M|            }
   71|       |
   72|   653k|            if (!remainingLine.length()) {
  ------------------
  |  Branch (72:17): [True: 12.2k, False: 640k]
  ------------------
   73|       |                /* All we had was space */
   74|  12.2k|                return {};
   75|   640k|            } else {
   76|       |                /* Are we at an operator? */
   77|   640k|                if (remainingLine[0] == ';' || remainingLine[0] == '=') {
  ------------------
  |  Branch (77:21): [True: 32.9k, False: 608k]
  |  Branch (77:48): [True: 253k, False: 354k]
  ------------------
   78|   286k|                    auto op = remainingLine.substr(0, 1);
   79|   286k|                    remainingLine.remove_prefix(1);
   80|   286k|                    return op;
   81|   354k|                } else {
   82|       |                    /* Are we at a quoted string? */
   83|   354k|                    if (remainingLine[0] == '\"') {
  ------------------
  |  Branch (83:25): [True: 30.3k, False: 323k]
  ------------------
   84|       |                        /* Remove first quote and start counting */
   85|  30.3k|                        remainingLine.remove_prefix(1);
   86|  30.3k|                        auto quote = remainingLine;
   87|  30.3k|                        int quoteLength = 0;
   88|       |
   89|       |                        /* Read anything until other double quote appears */
   90|  5.23M|                        while (remainingLine.length() && remainingLine[0] != '\"') {
  ------------------
  |  Branch (90:32): [True: 5.23M, False: 2.20k]
  |  Branch (90:58): [True: 5.20M, False: 28.1k]
  ------------------
   91|  5.20M|                            remainingLine.remove_prefix(1);
   92|  5.20M|                            quoteLength++;
   93|  5.20M|                        }
   94|       |
   95|       |                        /* We can't remove_prefix if we have nothing to remove */
   96|  30.3k|                        if (!remainingLine.length()) {
  ------------------
  |  Branch (96:29): [True: 2.20k, False: 28.1k]
  ------------------
   97|  2.20k|                            return {};
   98|  2.20k|                        }
   99|       |
  100|  28.1k|                        remainingLine.remove_prefix(1);
  101|  28.1k|                        return quote.substr(0, quoteLength);
  102|   323k|                    } else {
  103|       |                        /* Read anything until ; = space or end */
  104|   323k|                        std::string_view token = remainingLine;
  105|       |
  106|   323k|                        int tokenLength = 0;
  107|  8.99M|                        while (remainingLine.length() && remainingLine[0] != ';' && remainingLine[0] != '=' && !isspace(remainingLine[0])) {
  ------------------
  |  Branch (107:32): [True: 8.99M, False: 950]
  |  Branch (107:58): [True: 8.97M, False: 18.6k]
  |  Branch (107:85): [True: 8.73M, False: 235k]
  |  Branch (107:112): [True: 8.66M, False: 68.5k]
  ------------------
  108|  8.66M|                            remainingLine.remove_prefix(1);
  109|  8.66M|                            tokenLength++;
  110|  8.66M|                        }
  111|       |
  112|   323k|                        return token.substr(0, tokenLength);
  113|   323k|                    }
  114|   354k|                }
  115|   640k|            }
  116|       |
  117|       |            /* Nothing */
  118|      0|            return "";
  119|   653k|        }

