[
  {
    "path": ".github/workflows/codeql.yml",
    "content": "name: \"CodeQL\"\n\non:\n  push:\n    branches: [ 'master' ]\n  pull_request:\n    # The branches below must be a subset of the branches above\n    branches: [ 'master' ]\n  schedule:\n    - cron: '0 17 * * 2'\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ubuntu-latest\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n\n    strategy:\n      fail-fast: false\n      matrix:\n        language: [ 'cpp', 'javascript' ]\n        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]\n        # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support\n\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v3\n\n    # Initializes the CodeQL tools for scanning.\n    - name: Initialize CodeQL\n      uses: github/codeql-action/init@v2\n      with:\n        languages: ${{ matrix.language }}\n        # If you wish to specify custom queries, you can do so here or in a config file.\n        # By default, queries listed here will override any specified in a config file.\n        # Prefix the list here with \"+\" to use these queries and those in the config file.\n\n        # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs\n        queries: +security-and-quality\n\n    - run: |\n        echo \"Fetch submodules\"\n        git submodule update --init --recursive\n        \n    # Autobuild attempts to build any compiled languages  (C/C++, C#, Go, or Java).\n    # If this step fails, then you should remove it and run the build manually (see below)\n    - name: Autobuild\n      uses: github/codeql-action/autobuild@v2\n        \n        \n    # ℹ️ Command-line programs to run using the OS shell.\n    # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun\n\n    #   If the Autobuild fails above, remove it and uncomment the following three lines.\n    #   modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.\n\n    # - run: |\n    #   echo \"Run, Build Application using script\"\n    #   ./location_of_script_within_repo/buildscript.sh\n\n    - name: Perform CodeQL Analysis\n      uses: github/codeql-action/analyze@v2\n      with:\n        category: \"/language:${{matrix.language}}\"\n"
  },
  {
    "path": ".github/workflows/cpp.yml",
    "content": "name: C++ CI\n\non: [push]\n\njobs:\n\n  short_fuzzing:\n    runs-on: ubuntu-latest\n    steps:\n    - name: Build fuzzers\n      id: build\n      uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master\n      with:\n        oss-fuzz-project-name: 'uwebsockets'\n        language: c++\n    - name: Run fuzzers\n      uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master\n      with:\n        oss-fuzz-project-name: 'uwebsockets'\n        language: c++\n        fuzz-seconds: 600\n    - name: Upload crash\n      uses: actions/upload-artifact@v4\n      if: failure() && steps.build.outcome == 'success'\n      with:\n        name: artifacts\n        path: ./out/artifacts\n\n  build_windows:\n    runs-on: windows-latest\n    steps:\n      - name: Clone source\n        run: git clone --recursive https://github.com/uNetworking/uWebSockets.git\n      - name: Install libuv\n        run: |\n          vcpkg install libuv:x64-windows\n          cp C:\\vcpkg\\installed\\x64-windows\\bin\\uv.dll uWebSockets\\uv.dll\n      - uses: ilammy/msvc-dev-cmd@v1\n      - name: Build examples\n        run: |\n          cd uWebSockets\n          $Env:WITH_ZLIB='0'; $ENV:WITH_LTO='0'; $Env:CC='clang';\n          $ENV:CFLAGS='-I C:\\vcpkg\\installed\\x64-windows\\include';\n          $ENV:LDFLAGS='-L C:\\vcpkg\\installed\\x64-windows\\lib';\n          $ENV:CXX='clang++'; $ENV:EXEC_SUFFIX='.exe'; $ENV:WITH_LIBUV='1'; nmake\n          ls\n      - name: Run smoke test\n        run: |\n          cd uWebSockets\n          iwr https://deno.land/x/install/install.ps1 -useb | iex\n          Start-Process -NoNewWindow .\\Crc32\n          sleep 1\n          deno run --allow-net tests\\smoke.mjs\n          Stop-Process -Name Crc32\n\n  build_linux:\n\n    runs-on: ubuntu-latest\n    \n    steps:\n    - name: Clone source\n      run: git clone --recursive https://github.com/uNetworking/uWebSockets.git\n    - name: Build source\n      run: cmake -S uWebSockets/libdeflate -B uWebSockets/libdeflate && make -C uWebSockets/libdeflate && WITH_ASAN=1 WITH_LIBDEFLATE=1 make -C uWebSockets\n    - name: List binaries\n      run: ls uWebSockets\n    - name: Install Deno\n      run: curl -fsSL https://deno.land/x/install/install.sh | sh\n    - name: Run smoke test\n      run: make -C uWebSockets/tests smoke\n    - name: Run compliance test\n      run: make -C uWebSockets/tests compliance\n    - name: Run unit tests\n      run: make -C uWebSockets/tests\n    - name: Autobahn|Testsuite\n      run: ~/.deno/bin/deno run -A --unstable uWebSockets/autobahn/server-test.js\n      \n  build_osx:\n\n    runs-on: macos-latest\n    \n    steps:\n    - name: Clone source\n      run: git clone --recursive https://github.com/uNetworking/uWebSockets.git\n    - name: Build source\n      run: make -C uWebSockets\n    - name: List binaries\n      run: ls uWebSockets\n    - name: Install Deno\n      run: curl -fsSL https://deno.land/x/install/install.sh | sh\n    - name: Run smoke test\n      run: make -C uWebSockets/tests smoke\n    - name: Run unit tests\n      run: make -C uWebSockets/tests\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"uSockets\"]\n\tpath = uSockets\n\turl = https://github.com/uNetworking/uSockets.git\n[submodule \"fuzzing/libEpollFuzzer\"]\n\tpath = fuzzing/libEpollFuzzer\n\turl = https://github.com/uNetworking/libEpollFuzzer\n[submodule \"fuzzing/seed-corpus\"]\n\tpath = fuzzing/seed-corpus\n\turl = https://github.com/uNetworking/seed-corpus.git\n[submodule \"h1spec\"]\n\tpath = h1spec\n\turl = https://github.com/uNetworking/h1spec\n[submodule \"libdeflate\"]\n\tpath = libdeflate\n\turl = https://github.com/ebiggers/libdeflate\n"
  },
  {
    "path": "GNUmakefile",
    "content": "# This is the GNU Make shim for Linux and macOS\n\nDESTDIR ?=\nprefix ?= /usr/local\n\nexamples: default\n\t./build examples\n\nclean: default\n\t./build clean\n\ncapi: default\n\t./build capi\n\ninstall:\n\tmkdir -p \"$(DESTDIR)$(prefix)/include/uWebSockets\"\n\tcp -r src/* \"$(DESTDIR)$(prefix)/include/uWebSockets\"\n\nall: default\n\t./build all\n\ndefault:\n\t$(MAKE) -C uSockets\n\t$(CC) -fopenmp build.c -o build || $(CC) build.c -o build\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "Makefile",
    "content": "# This is the NMake shim for Windows (WIP)\n# Example: $Env:WITH_ZLIB='0'; $ENV:WITH_LTO='0'; $Env:CC='clang'; $ENV:CFLAGS='-I C:\\vcpkg\\installed\\x64-windows\\include'; $ENV:LDFLAGS='-L C:\\vcpkg\\installed\\x64-windows\\lib'; $ENV:CXX='clang++'; $ENV:EXEC_SUFFIX='.exe'; $ENV:WITH_LIBUV='1'; nmake\n\nexamples: default\n\t.\\build.exe examples || .\\a.exe examples\n\nclean: default\n\t.\\build.exe clean || .\\a.exe clean\n\ncapi: default\n\t.\\build.exe capi || .\\a.exe capi\n\nall: default\n\t.\\build.exe all || .\\a.exe all\n\ndefault:\n\tcd uSockets\n\t$(CC) $(CFLAGS) -DLIBUS_NO_SSL -std=c11 -Isrc -O3 -c src/*.c src/eventing/*.c src/crypto/*.c\n\tcd ..\n\t$(CC) build.c\n"
  },
  {
    "path": "README.md",
    "content": "\n<div align=\"center\">\n<img src=\"https://raw.githubusercontent.com/uNetworking/uWebSockets/master/misc/logo.svg\" height=\"180\" /><br>\n<i>Simple, secure</i><sup><a href=\"https://github.com/uNetworking/uWebSockets/tree/master/fuzzing#fuzz-testing-of-various-parsers-and-mocked-examples\">1</a></sup><i> & standards compliant</i><sup><a href=\"https://unetworking.github.io/uWebSockets.js/report.pdf\">2</a></sup><i> web server for the most demanding</i><sup><a href=\"https://github.com/uNetworking/uWebSockets/tree/master/benchmarks#benchmark-driven-development\">3</a></sup><i> of applications.</i> <a href=\"https://github.com/uNetworking/uWebSockets/blob/master/misc/READMORE.md\">Read more...</a>\n<br><br>\n\n<a href=\"https://github.com/uNetworking/uWebSockets/releases\"><img src=\"https://img.shields.io/github/v/release/uNetworking/uWebSockets\"></a> <a href=\"https://osv.dev/list?q=uwebsockets&affected_only=true&page=1&ecosystem=OSS-Fuzz\"><img src=\"https://oss-fuzz-build-logs.storage.googleapis.com/badges/uwebsockets.svg\" /></a> <img src=\"https://img.shields.io/badge/est.-2016-green\" />\n\n</div>\n<br><br>\n\n### :closed_lock_with_key: Optimized security\nBeing meticulously optimized for speed and memory footprint, µWebSockets is fast enough to do encrypted TLS 1.3 messaging quicker than most alternative servers can do even unencrypted, cleartext messaging<sup><a href=\"https://github.com/uNetworking/uWebSockets/tree/master/benchmarks#benchmark-driven-development\">3</a></sup>.\n\nFurthermore, we partake in Google's OSS-Fuzz with a ~95% daily fuzzing coverage<sup><a href=\"https://github.com/uNetworking/uWebSockets/blob/master/misc/Screenshot_20210915-004009.png?raw=true\">4</a></sup> with no sanitizer issues. LGTM scores us flawless A+ from having zero CodeQL alerts and we compile with pedantic warning levels.\n\n\n### :arrow_forward: Rapid scripting\nµWebSockets is written entirely in C & C++ but has a seamless integration for Node.js backends. This allows for rapid scripting of powerful apps, using widespread competence. See <a href=\"https://github.com/uNetworking/uWebSockets.js\">µWebSockets.js</a>.\n\n### :crossed_swords: Battle proven\nWe've been fully standards compliant with a perfect Autobahn|Testsuite score since 2016<sup><a href=\"https://unetworking.github.io/uWebSockets.js/report.pdf\">2</a></sup>. µWebSockets powers many of the biggest crypto exchanges in the world, handling trade volumes of multiple billions of USD every day. If you trade crypto, chances are you do so via µWebSockets.\n\n### :battery: Batteries included\nDesigned around a convenient URL router with wildcard & parameter support - paired with efficient pub/sub features for WebSockets. µWebSockets should be the obvious, complete starting point for any real-time web project with high demands.\n\nStart building your Http & WebSocket apps in no time; <a href=\"https://github.com/uNetworking/uWebSockets/blob/master/misc/READMORE.md\">read the user manual</a> and <a href=\"https://github.com/uNetworking/uWebSockets/tree/master/examples\">see examples</a>. You can browse our <a href=\"https://unetworking.github.io/uWebSockets.js/generated/\">TypeDoc</a> for a quick overview.\n\n```c++\n/* One app per thread; spawn as many as you have CPU-cores and let uWS share the listening port */\nuWS::SSLApp({\n\n    /* These are the most common options, fullchain and key. See uSockets for more options. */\n    .cert_file_name = \"cert.pem\",\n    .key_file_name = \"key.pem\"\n    \n}).get(\"/hello/:name\", [](auto *res, auto *req) {\n\n    /* You can efficiently stream huge files too */\n    res->writeStatus(\"200 OK\")\n       ->writeHeader(\"Content-Type\", \"text/html; charset=utf-8\")\n       ->write(\"<h1>Hello \")\n       ->write(req->getParameter(\"name\"))\n       ->end(\"!</h1>\");\n    \n}).ws<UserData>(\"/*\", {\n\n    /* Just a few of the available handlers */\n    .open = [](auto *ws) {\n        ws->subscribe(\"oh_interesting_subject\");\n    },\n    .message = [](auto *ws, std::string_view message, uWS::OpCode opCode) {\n        ws->send(message, opCode);\n    }\n    \n}).listen(9001, [](auto *listenSocket) {\n\n    if (listenSocket) {\n        std::cout << \"Listening on port \" << 9001 << std::endl;\n    } else {\n        std::cout << \"Failed to load certs or to bind to port\" << std::endl;\n    }\n    \n}).run();\n```\n### :briefcase: Commercially supported\n<a href=\"https://github.com/uNetworking\">uNetworking AB</a> is a Swedish consulting & contracting company dealing with anything related to µWebSockets; development, support and customer success.\n\nDon't hesitate <a href=\"mailto:alexhultman@gmail.com\">sending a mail</a> if you're building something large, in need of advice or having other business inquiries in mind. We'll figure out what's best for both parties and make sure you're not falling into common pitfalls.\n\nSpecial thanks to BitMEX, Bitfinex, Google, Coinbase, Bitwyre, AppDrag and deepstreamHub for allowing the project itself to thrive on GitHub since 2016 - this project would not be possible without these beautiful companies.\n\n### :wrench: Customizable architecture\nµWebSockets builds on <a href=\"https://github.com/uNetworking/uSockets\">µSockets</a>, a foundation library implementing eventing, networking and cryptography in three different layers. Every layer has multiple implementations and you control the compiled composition with flags. There are currently five event-loop integrations; libuv, ASIO, GCD and raw epoll/kqueue.\n\nIn a nutshell:\n\n* `WITH_WOLFSSL=1 WITH_LIBUV=1 make examples` builds examples utilizing WolfSSL and libuv\n* `WITH_OPENSSL=1 make examples` builds examples utilizing OpenSSL and the native kernel\n\nSee µSockets for an up-to-date list of flags and a more detailed explanation.\n\n### :handshake: Permissively licensed\nIntellectual property, all rights reserved.\n\nWhere such explicit notice is given, source code is licensed Apache License 2.0 which is a permissive OSI-approved license with very few limitations. Modified \"forks\" should be of nothing but licensed source code, and be made available under another product name. If you're uncertain about any of this, please ask before assuming.\n"
  },
  {
    "path": "autobahn/fuzzingclient.json",
    "content": "{\n  \"outdir\": \"./reports/servers\",\n  \"servers\": [\n    {\n      \"agent\": \"uWebSockets\",\n      \"url\": \"ws://localhost:9001\"\n    }\n  ],\n  \"cases\": [\n    \"1.*\",\n    \"2.*\",\n    \"3.*\",\n    \"4.*\",\n    \"5.*\",\n    \"6.*\",\n    \"7.*\",\n    \"9.*\",\n    \"10.*\",\n    \"11.*\",\n    \"12.*\",\n    \"13.*\"\n  ],\n  \"exclude-cases\": [\n  ],\n  \"exclude-agent-cases\": {}\n}\n"
  },
  {
    "path": "autobahn/server-test.js",
    "content": "// Based on https://github.com/denoland/fastwebsockets/blob/main/autobahn/server-test.js\n\nimport { $ } from \"https://deno.land/x/dax/mod.ts\";\n\nconst pwd = new URL(\".\", import.meta.url).pathname;\n\nconst AUTOBAHN_TESTSUITE_DOCKER =\n  \"crossbario/autobahn-testsuite:0.8.2@sha256:519915fb568b04c9383f70a1c405ae3ff44ab9e35835b085239c258b6fac3074\";\n\nconst server = $`uWebSockets/EchoServer`.spawn();\nawait $`docker run --name fuzzingserver\t-v ${pwd}/fuzzingclient.json:/fuzzingclient.json:ro\t-v ${pwd}/reports:/reports -p 9001:9001\t--net=host --rm\t${AUTOBAHN_TESTSUITE_DOCKER} wstest -m fuzzingclient -s fuzzingclient.json`.cwd(pwd);\n\nconst result = Object.values(JSON.parse(Deno.readTextFileSync(\"./uWebSockets/autobahn/reports/servers/index.json\"))[\"uWebSockets\"]);\n\nfunction failed(name) {\n  return name != \"OK\" && name != \"INFORMATIONAL\" && name != \"NON-STRICT\";\n}\n\nconsole.log(JSON.stringify(result, null, 2));\n\nconst failedtests = result.filter((outcome) => failed(outcome.behavior) || failed(outcome.behaviorClose));\n\nconsole.log(\n  `%c${result.length - failedtests.length} / ${result.length} tests OK`,\n  `color: ${failedtests.length == 0 ? \"green\" : \"red\"}`,\n);\n\nDeno.exit(failedtests.length == 0 ? 0 : 1);\n"
  },
  {
    "path": "benchmarks/Makefile",
    "content": "default:\n\tg++ -flto -march=native parser.cpp -O3 -I../uSockets/src -o parser\n\tclang -flto -O3 -DLIBUS_USE_OPENSSL -I../uSockets/src ../uSockets/src/*.c ../uSockets/src/eventing/*.c ../uSockets/src/crypto/*.c broadcast_test.c load_test.c scale_test.c -c\n\tclang++ -flto -O3 -DLIBUS_USE_OPENSSL -I../uSockets/src ../uSockets/src/crypto/*.cpp -c -std=c++17\n\tclang++ -flto -O3 -DLIBUS_USE_OPENSSL `ls *.o | grep -Ev \"load_test|scale_test\"` -lssl -lcrypto -o broadcast_test\n\tclang++ -flto -O3 -DLIBUS_USE_OPENSSL `ls *.o | grep -Ev \"broadcast_test|scale_test\"` -lssl -lcrypto -lz -o load_test\n\tclang++ -flto -O3 -DLIBUS_USE_OPENSSL `ls *.o | grep -Ev \"broadcast_test|load_test\"` -lssl -lcrypto -o scale_test\n\n"
  },
  {
    "path": "benchmarks/README.md",
    "content": "# More recent benchmarks\nIt was a while ago this page was written (and it needs updating), so here are the most recent benchmarks against the top competition we know of:\n\nv20 | v21\n--- | ---\n![](../misc/fastwebsockets.png) | ![](../misc/fastwebsockets_io_uring.png)\n\n\n# Benchmark-driven development\nMaking decisions based on scientific benchmarking **while** you develop can guide you to create very efficient solutions if you have the dicipline to follow through. µWebSockets performs with **98%** the theoretical maximum for any user space Linux process [this was written before io_uring was added to Linux] - if anything would ever be faster, it would only be so by less than 2%. We know of no such project.\n\nHttp | WebSockets\n--- | ---\n![](../misc/bigshot_lineup.png) | ![](../misc/websocket_lineup.png)\n\nBecause of the big lead in cleartext performance, it's actually possible to enable TLS 1.3 encryption in µWebSockets and still beat most of the competition in an unfair cleartext-vs-encrypted run. Performance retention of TLS 1.3 encryption with µWebSockets is about 60%, so you do the math.\n\nAll of this is possible thanks to extensive benchmarking of many discarded prototypes & designs during development. The very first thing done in this project was to benchmark the Linux kernel against itself, to get a clear idea of expected maximum performance and thus a performance budget on this platform.\n\nFrom that point every line of code was benchmarked against the budget and thrown away if it failed the vision. Today µWebSockets does WebSocket messaging without any significant overhead, making it very unlikely to ever be outperformed.\n\nOf course, memory usage has always been a big factor in this. The name µWebSockets is meant to signify \"small WebSockets\" and comes from the memory optimizations made throughout. Holding many WebSockets should not require lots of RAM.\n\nIf you're looking for a performant solution, look no further.\n\n## Common benchmarking mistakes\nIt is very common, extremely common in fact, that people try and benchmark µWebSockets using a scripted Node.js client such as autocannon, ws, or anything similar. It might seem like an okay method but it really isn't. µWebSockets is 12x faster than Node.js, so trying to stress µWebSockets using Node.js is almost impossible. Maybe if you have a 16-core CPU and dedicate 15 cores to Node.js and 1 core to µWebSockets.\n\nSo whatever you do, it is of greatest importance that you actually **do check and make sure that µWebSockets is being stressed to 100% CPU-time** before noting the result. If it isn't, then you're not really benchmarking µWebSockets - you're benchmarking your client, trying to stress µWebSockets! Please don't make this mistake.\n\n## Why \"hello world\" benchmarking?\n\nContrary to popular belief, \"hello world benchmarks\" are the most accurate and realistic gauges of performance for the kind of applications µWebSockets is designed for:\n\n* IO-gaming (latency)\n* Signalling (memory overhead)\n* Trading (latency)\n* Finance (latency)\n* Chatting (memory overhead)\n* Notifications (memory overhead)\n\nMost business applications of the above mentioned categories are implemented without a central on-disk DB, blocking or severely limiting hot-path performance. As such, web IO becomes a significant part of overall bottleneck, if not the only bottleneck. Message echoing of around 1-16 kB or even as small as 512 bytes is a good test of the overall server plumbing (receive -> timeout clear -> emit to app -> timeout set -> send) for these applications.\n\nOf course, if you build an app that *absolutely must* have an on-disk SQL DB central to all hot-paths, then µWebSockets is not the right tool for your app. Keep in mind that, finding a case where µWebSockets makes no difference, does not mean µWebSockets never makes a difference.\n"
  },
  {
    "path": "benchmarks/broadcast_test.c",
    "content": "/* This benchmark establishes _connections_ number of WebSocket\n   clients, then iteratively performs the following:\n\n   1. Send one message for every client.\n   2. Wait for the quadratic (_connections_^2) amount of responses from the server.\n   3. Once received all expected bytes, repeat by going to step 1.\n\n   Every 4 seconds we print the current average \"iterations per second\".\n   */\n\n#include <libusockets.h>\nint SSL;\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\nunsigned char web_socket_request[26] = {130, 128 | 20, 1, 2, 3, 4};\n\nchar request[] = \"GET / HTTP/1.1\\r\\n\"\n                 \"Upgrade: websocket\\r\\n\"\n                 \"Connection: Upgrade\\r\\n\"\n                 \"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\\r\\n\"\n                 \"Host: server.example.com\\r\\n\"\n                 \"Sec-WebSocket-Version: 13\\r\\n\\r\\n\";\nchar *host;\nint port;\nint connections;\n\nint satisfied_sockets;\nint iterations;\n\nstruct http_socket {\n    /* How far we have streamed our websocket request */\n    int offset;\n\n    /* How far we have streamed our upgrade request */\n    int upgrade_offset;\n\n    /* Are we upgraded? */\n    int is_upgraded;\n\n    /* Bytes received */\n    int bytes_received;\n};\n\n/* We track upgraded websockets */\nvoid **web_sockets;\nint num_web_sockets;\n\n/* We don't need any of these */\nvoid noop(struct us_loop_t *loop) {\n\n}\n\nvoid start_iteration() {\n    for (int i = 0; i < num_web_sockets; i++) {\n        struct us_socket_t *s = (struct us_socket_t *) web_sockets[i];\n        struct http_socket *http_socket = (struct http_socket *) us_socket_ext(SSL, s);\n\n        http_socket->offset = us_socket_write(SSL, s, (char *) web_socket_request, sizeof(web_socket_request), 0);\n    }\n}\n\nvoid next_connection(struct us_socket_t *s) {\n    /* Add this connection to our array */\n    web_sockets[num_web_sockets++] = s;\n\n    /* We could wait with this until properly upgraded */\n    if (--connections) {\n        us_socket_context_connect(SSL, us_socket_context(SSL, s), host, port, NULL, 0, sizeof(struct http_socket));\n    } else {\n        printf(\"Running benchmark now...\\n\");\n        start_iteration();\n\n        us_socket_timeout(SSL, s, LIBUS_TIMEOUT_GRANULARITY);\n    }\n}\n\nstruct us_socket_t *on_http_socket_writable(struct us_socket_t *s) {\n    struct http_socket *http_socket = (struct http_socket *) us_socket_ext(SSL, s);\n\n    /* Are we still not upgraded yet? */\n    if (http_socket->upgrade_offset < sizeof(request) - 1) {\n        http_socket->upgrade_offset += us_socket_write(SSL, s, request + http_socket->upgrade_offset, sizeof(request) - 1 - http_socket->upgrade_offset, 0);\n    } else {\n        /* Stream whatever is remaining of the request */\n        http_socket->offset += us_socket_write(SSL, s, (char *) web_socket_request + http_socket->offset, sizeof(web_socket_request) - http_socket->offset, 0);\n    }\n\n    return s;\n}\n\nstruct us_socket_t *on_http_socket_close(struct us_socket_t *s, int code, void *reason) {\n\n    printf(\"Client was disconnected, exiting!\\n\");\n    exit(-1);\n\n    return s;\n}\n\nstruct us_socket_t *on_http_socket_end(struct us_socket_t *s) {\n    return us_socket_close(SSL, s, 0, NULL);\n}\n\nstruct us_socket_t *on_http_socket_data(struct us_socket_t *s, char *data, int length) {\n    /* Get socket extension and the socket's context's extension */\n    struct http_socket *http_socket = (struct http_socket *) us_socket_ext(SSL, s);\n\n    /* Are we already upgraded? */\n    if (http_socket->is_upgraded) {\n        http_socket->bytes_received += length;\n\n        if (http_socket->bytes_received == (sizeof(web_socket_request) - 4) * num_web_sockets) {\n            satisfied_sockets++;\n            http_socket->bytes_received = 0;\n\n            if (satisfied_sockets == num_web_sockets) {\n                iterations++;\n                satisfied_sockets = 0;\n\n                start_iteration();\n            }\n        }\n    } else {\n        /* We assume the server is not sending anything immediately following upgrade and that we get rnrn in one chunk */\n        if (length >= 4 && data[length - 1] == '\\n' && data[length - 2] == '\\r' && data[length - 3] == '\\n' && data[length - 4] == '\\r') {\n            http_socket->is_upgraded = 1;\n            next_connection(s);\n        }\n    }\n\n    return s;\n}\n\nstruct us_socket_t *on_http_socket_open(struct us_socket_t *s, int is_client, char *ip, int ip_length) {\n    struct http_socket *http_socket = (struct http_socket *) us_socket_ext(SSL, s);\n\n    /* Reset offsets */\n    http_socket->offset = 0;\n    http_socket->is_upgraded = 0;\n    http_socket->bytes_received = 0;\n\n    /* Send an upgrade request */\n    http_socket->upgrade_offset = us_socket_write(SSL, s, request, sizeof(request) - 1, 0);\n\n    return s;\n}\n\nstruct us_socket_t *on_http_socket_timeout(struct us_socket_t *s) {\n    /* Print current statistics */\n    printf(\"Iterations/second (%d clients): %f\\n\", num_web_sockets, ((float)iterations) / LIBUS_TIMEOUT_GRANULARITY);\n\n    iterations = 0;\n    us_socket_timeout(SSL, s, LIBUS_TIMEOUT_GRANULARITY);\n\n    return s;\n}\n\nint main(int argc, char **argv) {\n\n    /* Parse host and port */\n    if (argc != 5) {\n        printf(\"Usage: connections host port ssl\\n\");\n        return 0;\n    }\n\n    port = atoi(argv[3]);\n    host = malloc(strlen(argv[2]) + 1);\n    memcpy(host, argv[2], strlen(argv[2]) + 1);\n    connections = atoi(argv[1]);\n    SSL = atoi(argv[4]);\n\n    /* Allocate room for every socket */\n    web_sockets = (void **) malloc(sizeof(void *) * connections);\n\n    /* Create the event loop */\n    struct us_loop_t *loop = us_create_loop(0, noop, noop, noop, 0);\n\n    /* Create a socket context for HTTP */\n    struct us_socket_context_options_t options = {};\n    struct us_socket_context_t *http_context = us_create_socket_context(SSL, loop, 0, options);\n\n    /* Set up event handlers */\n    us_socket_context_on_open(SSL, http_context, on_http_socket_open);\n    us_socket_context_on_data(SSL, http_context, on_http_socket_data);\n    us_socket_context_on_writable(SSL, http_context, on_http_socket_writable);\n    us_socket_context_on_close(SSL, http_context, on_http_socket_close);\n    us_socket_context_on_timeout(SSL, http_context, on_http_socket_timeout);\n    us_socket_context_on_end(SSL, http_context, on_http_socket_end);\n\n    /* Start making HTTP connections */\n    us_socket_context_connect(SSL, http_context, host, port, NULL, 0, sizeof(struct http_socket));\n\n    us_loop_run(loop);\n}\n"
  },
  {
    "path": "benchmarks/load_test.c",
    "content": "#define _DEFAULT_SOURCE\n\n#ifdef __APPLE__\n#include <libkern/OSByteOrder.h>\n#define htobe16(x) OSSwapHostToBigInt16(x)\n#define htole16(x) OSSwapHostToLittleInt16(x)\n#define be16toh(x) OSSwapBigToHostInt16(x)\n#define le16toh(x) OSSwapLittleToHostInt16(x)\n#define htobe32(x) OSSwapHostToBigInt32(x)\n#define htole32(x) OSSwapHostToLittleInt32(x)\n#define be32toh(x) OSSwapBigToHostInt32(x)\n#define le32toh(x) OSSwapLittleToHostInt32(x)\n#define htobe64(x) OSSwapHostToBigInt64(x)\n#define htole64(x) OSSwapHostToLittleInt64(x)\n#define be64toh(x) OSSwapBigToHostInt64(x)\n#define le64toh(x) OSSwapLittleToHostInt64(x)\n#else\n#include <endian.h>\n#endif\n\n#include <stdint.h>\n#include <libusockets.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <zlib.h>\n#include <time.h>\n\n/** @brief Structure to hold per-socket state */\ntypedef struct {\n    int offset;            // Bytes sent of the WebSocket request\n    int upgrade_offset;    // Bytes sent of the upgrade request\n    int is_upgraded;       // Whether the socket has been upgraded to WebSocket\n    int outstanding_bytes; // Expected bytes to receive for echo completion\n} SocketState;\n\n/** @brief Structure to hold benchmark configuration */\ntypedef struct {\n    char *host;                          // Target server host\n    int port;                            // Target server port\n    int SSL;                             // Whether to use SSL (0 or 1)\n    int deflate;                         // Whether to use compression (0 or 1)\n    int payload_size;                    // Size of the payload in bytes\n    unsigned char *web_socket_request;   // Precomputed WebSocket request frame\n    int web_socket_request_size;         // Size of the request frame\n    int web_socket_request_response_size;// Expected response size\n    char *upgrade_request;               // HTTP upgrade request string\n    int upgrade_request_length;          // Length of the upgrade request\n} BenchmarkConfig;\n\n// Static variables for configuration and shared state\nstatic BenchmarkConfig config;\nstatic int connections;  // Number of remaining connections to establish\nstatic int responses = 0;// Number of responses received\n\n// Predefined static data\nstatic char request_deflate[] = \"GET / HTTP/1.1\\r\\nUpgrade: websocket\\r\\nConnection: Upgrade\\r\\nSec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\\r\\nSec-WebSocket-Extensions: permessage-deflate\\r\\nHost: server.example.com\\r\\nSec-WebSocket-Version: 13\\r\\n\\r\\n\";\nstatic char request_text[] = \"GET / HTTP/1.1\\r\\nUpgrade: websocket\\r\\nConnection: Upgrade\\r\\nSec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\\r\\nHost: server.example.com\\r\\nSec-WebSocket-Version: 13\\r\\n\\r\\n\";\n\n/**\n * @brief Initializes a text WebSocket request\n * @param size Payload size in bytes\n * @param config Pointer to the BenchmarkConfig to populate\n */\nvoid init_text_request(int size, BenchmarkConfig *config) {\n    if (size <= 125) {\n        config->web_socket_request_size = size + 6;\n        config->web_socket_request = malloc(config->web_socket_request_size);\n        config->web_socket_request[0] = 130; // FIN + opcode 1 (text)\n        config->web_socket_request[1] = 128 | size; // Mask bit + length\n        config->web_socket_request[2] = 1;\n        config->web_socket_request[3] = 2;\n        config->web_socket_request[4] = 3;\n        config->web_socket_request[5] = 4;\n        memset(config->web_socket_request + 6, 'T', size);\n    } else if (size <= 65535) {\n        config->web_socket_request_size = size + 8;\n        config->web_socket_request = malloc(config->web_socket_request_size);\n        config->web_socket_request[0] = 130;\n        config->web_socket_request[1] = 128 | 126;\n        uint16_t len = htobe16(size);\n        memcpy(&config->web_socket_request[2], &len, 2);\n        config->web_socket_request[4] = 1;\n        config->web_socket_request[5] = 2;\n        config->web_socket_request[6] = 3;\n        config->web_socket_request[7] = 4;\n        memset(config->web_socket_request + 8, 'T', size);\n    } else {\n        config->web_socket_request_size = size + 14;\n        config->web_socket_request = malloc(config->web_socket_request_size);\n        config->web_socket_request[0] = 130;\n        config->web_socket_request[1] = 128 | 127;\n        uint64_t len = htobe64(size);\n        memcpy(&config->web_socket_request[2], &len, 8);\n        config->web_socket_request[10] = 1;\n        config->web_socket_request[11] = 2;\n        config->web_socket_request[12] = 3;\n        config->web_socket_request[13] = 4;\n        memset(config->web_socket_request + 14, 'T', size);\n    }\n    config->web_socket_request_response_size = config->web_socket_request_size;\n}\n\n/**\n * @brief Initializes a deflated WebSocket request\n * @param size Size of the uncompressed payload in bytes\n * @param config Pointer to the BenchmarkConfig to populate\n */\nvoid init_deflated_request(int size, BenchmarkConfig *config) {\n    const char placeholder[] = \"{\\\"userId\\\":12345,\\\"action\\\":\\\"purchase\\\",\\\"items\\\":[{\\\"id\\\":\\\"A1B2C3\\\",\\\"name\\\":\\\"Wireless Mouse\\\",\\\"price\\\":25.99,\\\"quantity\\\":1},{\\\"id\\\":\\\"D4E5F6\\\",\\\"name\\\":\\\"Mechanical Keyboard\\\",\\\"price\\\":89.99,\\\"quantity\\\":1}],\\\"payment\\\":{\\\"method\\\":\\\"credit_card\\\",\\\"transactionId\\\":\\\"XYZ987654321\\\",\\\"status\\\":\\\"approved\\\"},\\\"timestamp\\\":\\\"2025-02-20T15:30:00Z\\\"};\";\n    char *json_message = malloc(size);\n    int placeholder_len = sizeof(placeholder) - 1;\n    printf(\"Using placeholder of %d bytes\\n\", placeholder_len);\n    for (int i = 0; i < size; i += placeholder_len) {\n        int copy_len = (i + placeholder_len <= size) ? placeholder_len : size - i;\n        memcpy(json_message + i, placeholder, copy_len);\n    }\n\n    z_stream defstream;\n    defstream.zalloc = Z_NULL;\n    defstream.zfree = Z_NULL;\n    defstream.opaque = Z_NULL;\n    deflateInit2(&defstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY);\n    uLongf compressed_max_size = deflateBound(&defstream, (uLong)size);\n    Bytef *compressed_data = malloc(compressed_max_size);\n\n    defstream.avail_in = (uInt)size;\n    defstream.next_in = (Bytef *)json_message;\n    defstream.avail_out = (uInt)compressed_max_size;\n    defstream.next_out = compressed_data;\n    int res = deflate(&defstream, Z_SYNC_FLUSH);\n    if (res != Z_OK) {\n        printf(\"Deflation failed: %d\\n\", res);\n        exit(1);\n    }\n    uLongf compressed_size = defstream.total_out - 4;\n    deflateEnd(&defstream);\n    free(json_message);\n\n    unsigned char mask[4] = {0, 0, 0, 0};\n    for (uLongf i = 0; i < compressed_size; i++) {\n        compressed_data[i] ^= mask[i % 4];\n    }\n\n    unsigned char header[14];\n    int header_len;\n    if (compressed_size <= 125) {\n        header_len = 6;\n        header[0] = 0xC2; // FIN + RSV1 + Opcode 2\n        header[1] = 0x80 | compressed_size;\n        memcpy(header + 2, mask, 4);\n    } else if (compressed_size <= 65535) {\n        header_len = 8;\n        header[0] = 0xC2;\n        header[1] = 0x80 | 126;\n        header[2] = (compressed_size >> 8) & 0xFF;\n        header[3] = compressed_size & 0xFF;\n        memcpy(header + 4, mask, 4);\n    } else {\n        header_len = 14;\n        header[0] = 0xC2;\n        header[1] = 0x80 | 127;\n        for (int i = 0; i < 8; i++) {\n            header[2 + i] = (compressed_size >> (56 - i * 8)) & 0xFF;\n        }\n        memcpy(header + 10, mask, 4);\n    }\n\n    config->web_socket_request_size = header_len + compressed_size;\n    config->web_socket_request = malloc(config->web_socket_request_size);\n    memcpy(config->web_socket_request, header, header_len);\n    memcpy(config->web_socket_request + header_len, compressed_data, compressed_size);\n    free(compressed_data);\n\n    int server_will_compress = 0;\n    if (server_will_compress) {\n        config->web_socket_request_response_size = config->web_socket_request_size;\n    } else {\n        if (size <= 125) {\n            config->web_socket_request_response_size = 6 + size;\n        } else if (size <= 65535) {\n            config->web_socket_request_response_size = 8 + size;\n        } else {\n            config->web_socket_request_response_size = 14 + size;\n        }\n    }\n}\n\n/**\n * @brief Initiates the next connection or starts the benchmark\n * @param s Current socket\n */\nvoid next_connection(struct us_socket_t *s) {\n    if (--connections) {\n        us_socket_context_connect(config.SSL, us_socket_context(config.SSL, s), config.host, config.port, NULL, 0, sizeof(SocketState));\n    } else {\n        printf(\"Running benchmark now...\\n\");\n        us_socket_timeout(config.SSL, s, LIBUS_TIMEOUT_GRANULARITY);\n    }\n}\n\n/** @brief Handler for when a socket becomes writable */\nstruct us_socket_t *on_http_socket_writable(struct us_socket_t *s) {\n    SocketState *state = (SocketState *)us_socket_ext(config.SSL, s);\n    if (state->upgrade_offset < config.upgrade_request_length) {\n        state->upgrade_offset += us_socket_write(config.SSL, s, config.upgrade_request + state->upgrade_offset, config.upgrade_request_length - state->upgrade_offset, 0);\n        if (state->upgrade_offset == config.upgrade_request_length) {\n            next_connection(s);\n        }\n    } else {\n        state->offset += us_socket_write(config.SSL, s, (char *)config.web_socket_request + state->offset, config.web_socket_request_size - state->offset, 0);\n    }\n    return s;\n}\n\n/** @brief Handler for socket closure */\nstruct us_socket_t *on_http_socket_close(struct us_socket_t *s, int code, void *reason) {\n    printf(\"Closed!\\n\");\n    return s;\n}\n\n/** @brief Handler for socket end */\nstruct us_socket_t *on_http_socket_end(struct us_socket_t *s) {\n    return us_socket_close(config.SSL, s, 0, NULL);\n}\n\n/** @brief Handler for incoming data */\nstruct us_socket_t *on_http_socket_data(struct us_socket_t *s, char *data, int length) {\n    SocketState *state = (SocketState *)us_socket_ext(config.SSL, s);\n    if (state->is_upgraded) {\n        state->outstanding_bytes -= length;\n        if (state->outstanding_bytes == 0) {\n            state->offset = us_socket_write(config.SSL, s, (char *)config.web_socket_request, config.web_socket_request_size, 0);\n            state->outstanding_bytes = config.web_socket_request_response_size - 4;\n            responses++;\n        } else if (state->outstanding_bytes < 0) {\n            printf(\"ERROR: outstanding bytes negative!\\n\");\n            exit(0);\n        }\n    } else {\n        if (length >= 4 && memcmp(data + length - 4, \"\\r\\n\\r\\n\", 4) == 0) {\n            printf(\"Response: %.*s\\n\", length, data);\n            state->offset = us_socket_write(config.SSL, s, (char *)config.web_socket_request, config.web_socket_request_size, 0);\n            state->outstanding_bytes = config.web_socket_request_response_size - 4;\n            state->is_upgraded = 1;\n        }\n    }\n    return s;\n}\n\n/** @brief Handler for socket opening */\nstruct us_socket_t *on_http_socket_open(struct us_socket_t *s, int is_client, char *ip, int ip_length) {\n    SocketState *state = (SocketState *)us_socket_ext(config.SSL, s);\n    state->offset = 0;\n    state->is_upgraded = 0;\n    state->upgrade_offset = us_socket_write(config.SSL, s, config.upgrade_request, config.upgrade_request_length, 0);\n    if (state->upgrade_offset == config.upgrade_request_length) {\n        next_connection(s);\n    }\n    return s;\n}\n\n/** @brief Handler for socket timeout */\nstruct us_socket_t *on_http_socket_timeout(struct us_socket_t *s) {\n    printf(\"Msg/sec: %f\\n\", ((float)responses) / LIBUS_TIMEOUT_GRANULARITY);\n    responses = 0;\n    us_socket_timeout(config.SSL, s, LIBUS_TIMEOUT_GRANULARITY);\n    return s;\n}\n\n// Empty loop callbacks required by libusockets\nvoid on_wakeup(struct us_loop_t *loop) {}\nvoid on_pre(struct us_loop_t *loop) {}\nvoid on_post(struct us_loop_t *loop) {}\n\n/**\n * @brief Main entry point for the WebSocket benchmark\n * @param argc Number of command-line arguments\n * @param argv Array of command-line arguments\n * @return Exit status\n */\nint main(int argc, char **argv) {\n    if (argc != 6 && argc != 7) {\n        printf(\"Usage: connections host port ssl deflate [payload_size_bytes]\\n\");\n        return 0;\n    }\n\n    // Initialize configuration\n    config.host = malloc(strlen(argv[2]) + 1);\n    memcpy(config.host, argv[2], strlen(argv[2]) + 1);\n    config.port = atoi(argv[3]);\n    connections = atoi(argv[1]);\n    config.SSL = atoi(argv[4]);\n    config.deflate = atoi(argv[5]);\n\n    // Set up upgrade request and WebSocket request based on deflate option\n    if (config.deflate) {\n        config.upgrade_request = request_deflate;\n        config.upgrade_request_length = sizeof(request_deflate) - 1;\n        config.payload_size = (argc == 7) ? atoi(argv[6]) : 5;\n        init_deflated_request(config.payload_size, &config);\n        printf(\"Using message size of %d bytes compressed down to %d bytes\\n\", config.payload_size, config.web_socket_request_size);\n    } else {\n        config.upgrade_request = request_text;\n        config.upgrade_request_length = sizeof(request_text) - 1;\n        if (argc == 7) {\n            config.payload_size = atoi(argv[6]);\n        } else {\n            config.payload_size = 20;\n        }\n        init_text_request(config.payload_size, &config);\n        printf(\"Using message size of %d bytes\\n\", config.payload_size);\n    }\n\n    // Create and run the event loop\n    struct us_loop_t *loop = us_create_loop(0, on_wakeup, on_pre, on_post, 0);\n    struct us_socket_context_options_t options = {0};\n    struct us_socket_context_t *http_context = us_create_socket_context(config.SSL, loop, 0, options);\n\n    // Register event handlers\n    us_socket_context_on_open(config.SSL, http_context, on_http_socket_open);\n    us_socket_context_on_data(config.SSL, http_context, on_http_socket_data);\n    us_socket_context_on_writable(config.SSL, http_context, on_http_socket_writable);\n    us_socket_context_on_close(config.SSL, http_context, on_http_socket_close);\n    us_socket_context_on_timeout(config.SSL, http_context, on_http_socket_timeout);\n    us_socket_context_on_end(config.SSL, http_context, on_http_socket_end);\n\n    // Start the first connection\n    us_socket_context_connect(config.SSL, http_context, config.host, config.port, NULL, 0, sizeof(SocketState));\n    us_loop_run(loop);\n\n    // Cleanup\n    free(config.host);\n    free(config.web_socket_request);\n    us_socket_context_free(config.SSL, http_context);\n    us_loop_free(loop);\n\n    return 0;\n}\n"
  },
  {
    "path": "benchmarks/parser.cpp",
    "content": "/* This is a fuzz test of the websocket parser */\n\n#define WIN32_EXPORT\n\n/* We test the websocket parser */\n#include \"../src/WebSocketProtocol.h\"\n\nunsigned int messages = 0;\n\nstruct Impl {\n    static bool refusePayloadLength(uint64_t length, uWS::WebSocketState<true> *wState, void *s) {\n\n        /* We need a limit */\n        if (length > 16000) {\n            return true;\n        }\n\n        /* Return ok */\n        return false;\n    }\n\n    static bool setCompressed(uWS::WebSocketState<true> *wState, void *s) {\n        /* We support it */\n        return true;\n    }\n\n    static void forceClose(uWS::WebSocketState<true> *wState, void *s, std::string_view reason = {}) {\n\n    }\n\n    static bool handleFragment(char *data, size_t length, unsigned int remainingBytes, int opCode, bool fin, uWS::WebSocketState<true> *webSocketState, void *s) {\n\n        if (opCode == uWS::TEXT) {\n            if (!uWS::protocol::isValidUtf8((unsigned char *)data, length)) {\n                /* Return break */\n                return true;\n            }\n        } else if (opCode == uWS::CLOSE) {\n            uWS::protocol::parseClosePayload((char *)data, length);\n        }\n\n        messages += 1;\n\n        /* Return ok */\n        return false;\n    }\n};\n\n#include <iostream>\n\nint web_socket_request_text_size;\nchar *web_socket_request_text;\n\nvoid init_medium_message(unsigned int size) {\n    if (size > 65536) {\n        printf(\"Error: message size must be smaller\\n\");\n        exit(0);\n    }\n\n    web_socket_request_text_size = size + 6 + 2; // 8 for big\n\n    web_socket_request_text = ((char *) malloc(32 + web_socket_request_text_size + 32)) + 32;\n    memset(web_socket_request_text, 'T', web_socket_request_text_size + 32);\n    web_socket_request_text[0] = 130;\n    web_socket_request_text[1] = 254;\n    uint16_t msg_size = htobe16(size);\n    memcpy(&web_socket_request_text[2], &msg_size, 2);\n    web_socket_request_text[4] = 1;\n    web_socket_request_text[5] = 2;\n    web_socket_request_text[6] = 3;\n    web_socket_request_text[7] = 4;\n}\n\nint main() {\n\n    init_medium_message(1024);\n\n    /* Create the parser state */\n    uWS::WebSocketState<true> state;\n\n    unsigned char pre[32];\n    unsigned char web_socket_request_text_small[26] = {130, 128 | 20, 1, 2, 3, 4};\n    unsigned char post[32];\n\n    uint16_t msg_size = htobe16(1024);\n\n    {\n        clock_t start = clock();\n\n        for (unsigned long long i = 0; i < 100000000; i++) {\n            \n            web_socket_request_text[0] = 130;\n            web_socket_request_text[1] = 254;\n            memcpy(&web_socket_request_text[2], &msg_size, 2);\n            web_socket_request_text[4] = 1;\n            web_socket_request_text[5] = 2;\n            web_socket_request_text[6] = 3;\n            web_socket_request_text[7] = 4;\n\n            // here we can either consume the whole message or consume the whole message minus 1 byte, causing a different path to be taken\n            uWS::WebSocketProtocol<true, Impl>::consume((char *) web_socket_request_text, web_socket_request_text_size-1, &state, nullptr);\n        }\n\n        clock_t stop = clock();\n        float seconds = ((float)(stop-start)/CLOCKS_PER_SEC);\n\n        std::cout << std::fixed << \"Parsed incomplete 1 kB messages per second: \" << ((float)messages / seconds) << std::endl;\n    }\n\n    {\n        messages = 0;\n        clock_t start = clock();\n\n        for (unsigned long long i = 0; i < 100000000; i++) {\n            \n            web_socket_request_text[0] = 130;\n            web_socket_request_text[1] = 254;\n            memcpy(&web_socket_request_text[2], &msg_size, 2);\n            web_socket_request_text[4] = 1;\n            web_socket_request_text[5] = 2;\n            web_socket_request_text[6] = 3;\n            web_socket_request_text[7] = 4;\n\n            // here we can either consume the whole message or consume the whole message minus 1 byte, causing a different path to be taken\n            uWS::WebSocketProtocol<true, Impl>::consume((char *) web_socket_request_text, web_socket_request_text_size, &state, nullptr);\n        }\n\n        clock_t stop = clock();\n        float seconds = ((float)(stop-start)/CLOCKS_PER_SEC);\n\n        std::cout << std::fixed << \"Parsed complete 1 kB messages per second: \" << ((float)messages / seconds) << std::endl;\n    }\n\n    return 0;\n}\n\n"
  },
  {
    "path": "benchmarks/scale_test.c",
    "content": "/* This is a scalability test for testing million(s) of pinging connections */\n\n#include <libusockets.h>\nint SSL;\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n#include <stdint.h>\n\nunsigned char web_socket_request[26] = {130, 128 | 20, 1, 2, 3, 4};\n\nchar request[] = \"GET / HTTP/1.1\\r\\n\"\n                 \"Upgrade: websocket\\r\\n\"\n                 \"Connection: Upgrade\\r\\n\"\n                 \"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\\r\\n\"\n                 \"Host: server.example.com\\r\\n\"\n                 \"Sec-WebSocket-Version: 13\\r\\n\\r\\n\";\nchar *host;\nint port;\nint connections;\n\n/* All the ips we as client can use */\nchar **ips;\nint num_ips;\n\n/* Send ping every 16 seconds */\nint WEBSOCKET_PING_INTERVAL = 8;\n\n/* We only establish 20k connections per address */\nint CONNECTIONS_PER_ADDRESS = 20000;\n\n/* How many connections a time */\nint BATCH_CONNECT = 1;\n\n/* Currently open and alive connections */\nint opened_connections;\n/* Dead connections */\nint closed_connections;\n\nstruct http_socket {\n    /* How far we have streamed our websocket request */\n    int offset;\n\n    /* How far we have streamed our upgrade request */\n    int upgrade_offset;\n};\n\nstruct us_socket_t *next_connection_failed = 0;\n\n/* We don't need any of these */\nvoid on_pre(struct us_loop_t *loop) {\n\n}\n\n/* This is not HTTP POST, it is merely an event emitted post loop iteration */\nvoid on_post(struct us_loop_t *loop) {\n\n}\n\nvoid next_connection(struct us_socket_t *s) {\n    /* We could wait with this until properly upgraded */\n    if (--connections/* > BATCH_CONNECT*/) {\n        /* Swap address */\n        int address = opened_connections / CONNECTIONS_PER_ADDRESS;\n\n        if (us_socket_context_connect(SSL, us_socket_context(SSL, s), host, port, ips[address], 0, sizeof(struct http_socket)) == 0) {\n            printf(\"Next connection failed immediately\\n\");\n\n            /* Try agsin next event loop iteration */\n            next_connection_failed = s;\n            us_wakeup_loop(us_socket_context_loop(0, us_socket_context(0, s)));\n\n        }\n    }\n}\n\nvoid on_wakeup(struct us_loop_t *loop) {\n    if (next_connection_failed) {\n        struct us_socket_t *s = next_connection_failed;\n        next_connection_failed = 0;\n        next_connection(s);\n    }\n}\n\nstruct us_socket_t *on_http_socket_writable(struct us_socket_t *s) {\n    struct http_socket *http_socket = (struct http_socket *) us_socket_ext(SSL, s);\n\n    /* Are we still not upgraded yet? */\n    if (http_socket->upgrade_offset < sizeof(request) - 1) {\n        http_socket->upgrade_offset += us_socket_write(SSL, s, request + http_socket->upgrade_offset, sizeof(request) - 1 - http_socket->upgrade_offset, 0);\n\n        /* Now we should be */\n        if (http_socket->upgrade_offset == sizeof(request) - 1) {\n            next_connection(s);\n\n            /* Make sure to send ping */\n            us_socket_timeout(SSL, s, WEBSOCKET_PING_INTERVAL);\n        }\n    } else {\n        /* Stream whatever is remaining of the request */\n        http_socket->offset += us_socket_write(SSL, s, (char *) web_socket_request + http_socket->offset, sizeof(web_socket_request) - http_socket->offset, 0);\n        if (http_socket->offset == sizeof(web_socket_request)) {\n            /* Reset timeout if we managed to */\n            us_socket_timeout(SSL, s, WEBSOCKET_PING_INTERVAL);\n        }\n    }\n\n    return s;\n}\n\nstruct us_socket_t *on_http_socket_close(struct us_socket_t *s, int code, void *reason) {\n\n    closed_connections++;\n    if (closed_connections % 1000 == 0) {\n        printf(\"Alive: %d, dead: %d\\n\", opened_connections, closed_connections);\n    }\n\n    return s;\n}\n\nstruct us_socket_t *on_http_socket_end(struct us_socket_t *s) {\n    return us_socket_close(SSL, s, 0, NULL);\n}\n\n// should never get a response!\nstruct us_socket_t *on_http_socket_data(struct us_socket_t *s, char *data, int length) {\n\n    // is this a broadcasted unix time in millis?\n    if (length % 10 == 0) {\n\n        // data sent first will come first, so it is oldest\n\n        struct timespec ts;\n        timespec_get(&ts, TIME_UTC);\n\n        int64_t millis = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;\n\n\n        int64_t received_millis;\n        memcpy(&received_millis, data + 2, 8);\n\n        static int counter;\n        static int max_latency;\n        static long average_latency;\n\n        int latency = millis - received_millis;\n\n        average_latency += latency;\n\n        if (max_latency < latency) {\n            max_latency = latency;\n        }\n\n        if (++counter % 10000 == 0) {\n            printf(\"Alive: %d, dead: %d\\n\", opened_connections, closed_connections);\n            printf(\"Max latency: %d ms\\n\", max_latency);\n            printf(\"Average latency: %ld ms\\n\\n\", average_latency / 10000);\n            max_latency = 0;\n            average_latency = 0;\n        }\n\n\n\n    }\n\n\n\n    return s;\n}\n\nstruct us_socket_t *on_http_socket_open(struct us_socket_t *s, int is_client, char *ip, int ip_length) {\n    struct http_socket *http_socket = (struct http_socket *) us_socket_ext(SSL, s);\n\n    /* Display number of opened connections */\n    opened_connections++;\n    if (opened_connections % 1000 == 0) {\n        printf(\"Alive: %d, dead: %d\\n\", opened_connections, closed_connections);\n    }\n\n    /* Send an upgrade request */\n    http_socket->upgrade_offset = us_socket_write(SSL, s, request, sizeof(request) - 1, 0);\n    if (http_socket->upgrade_offset == sizeof(request) - 1) {\n        next_connection(s);\n\n        /* Make sure to send ping */\n        us_socket_timeout(SSL, s, WEBSOCKET_PING_INTERVAL);\n    }\n\n    return s;\n}\n\n// here we should send a message as ping (part of the test)\nstruct us_socket_t *on_http_socket_timeout(struct us_socket_t *s) {\n    struct http_socket *http_socket = (struct http_socket *) us_socket_ext(SSL, s);\n\n    /* Send ping here */\n    http_socket->offset = us_socket_write(SSL, s, (char *) web_socket_request, sizeof(web_socket_request), 0);\n    if (http_socket->offset == sizeof(web_socket_request)) {\n        /* Reset timeout if we managed to */\n        us_socket_timeout(SSL, s, WEBSOCKET_PING_INTERVAL);\n    }\n\n    return s;\n}\n\nstruct us_socket_t *on_http_socket_connect_error(struct us_socket_t *s, int code) {\n\n    printf(\"Connection failed\\n\");\n\n    next_connection(s);\n\n    return s;\n}\n\nint main(int argc, char **argv) {\n\n    /* Parse host and port */\n    if (argc < 5) {\n        printf(\"Usage: connections host port ssl [ip ...]\\n\");\n        return 0;\n    }\n\n    port = atoi(argv[3]);\n    host = malloc(strlen(argv[2]) + 1);\n    memcpy(host, argv[2], strlen(argv[2]) + 1);\n    connections = atoi(argv[1]);\n    SSL = atoi(argv[4]);\n\n    /* Do we have ip addresses? */\n    if (argc > 5) {\n        ips = &argv[5];\n        num_ips = argc - 5;\n\n        for (int i = 0; i < num_ips; i++) {\n            printf(\"%s\\n\", ips[i]);\n        }\n    } else {\n        static char *default_ips[] = {\"\"};\n        ips = default_ips;\n        num_ips = 1;\n    }\n\n    /* Check so that we have enough ip addresses */\n    if (num_ips <= connections / CONNECTIONS_PER_ADDRESS) {\n        printf(\"You'll need more IP addresses for this run\\n\");\n        return 0;\n    }\n\n    /* Create the event loop */\n    struct us_loop_t *loop = us_create_loop(0, on_wakeup, on_pre, on_post, 0);\n\n    /* Create a socket context for HTTP */\n    struct us_socket_context_options_t options = {};\n    struct us_socket_context_t *http_context = us_create_socket_context(SSL, loop, 0, options);\n\n    /* Set up event handlers */\n    us_socket_context_on_open(SSL, http_context, on_http_socket_open);\n    us_socket_context_on_data(SSL, http_context, on_http_socket_data);\n    us_socket_context_on_writable(SSL, http_context, on_http_socket_writable);\n    us_socket_context_on_close(SSL, http_context, on_http_socket_close);\n    us_socket_context_on_timeout(SSL, http_context, on_http_socket_timeout);\n    us_socket_context_on_end(SSL, http_context, on_http_socket_end);\n    us_socket_context_on_connect_error(SSL, http_context, on_http_socket_connect_error);\n\n    /* Start making HTTP connections */\n    for (int i = 0; i < BATCH_CONNECT; i++) {\n        if (us_socket_context_connect(SSL, http_context, host, port, ips[0], 0, sizeof(struct http_socket)) == 0) {\n            printf(\"Connection failed immediately\\n\");\n            return 0;\n        }\n    }\n\n    us_loop_run(loop);\n}\n"
  },
  {
    "path": "build.c",
    "content": "#include \"build.h\"\n\nint main(int argc, char **argv) {\n    /* Some variables we need */\n    char *CXXFLAGS = strncpy(calloc(1024, 1), maybe(getenv(\"CXXFLAGS\")), 1024);\n    char *CFLAGS = strncpy(calloc(1024, 1), maybe(getenv(\"CFLAGS\")), 1024);\n    char *LDFLAGS = strncpy(calloc(1024, 1), maybe(getenv(\"LDFLAGS\")), 1024);\n    char *CC = strncpy(calloc(1024, 1), or_else(getenv(\"CC\"), \"cc\"), 1024);\n    char *CXX = strncpy(calloc(1024, 1), or_else(getenv(\"CXX\"), \"g++\"), 1024);\n    char *EXEC_SUFFIX = strncpy(calloc(1024, 1), maybe(getenv(\"EXEC_SUFFIX\")), 1024);\n\n    char *EXAMPLE_FILES[] = {\"SecureGzipFileServer\", \"Precompress\", \"EchoBody\", \"HelloWorldThreaded\", \"Http3Server\", \"Broadcast\", \"HelloWorld\", \"Crc32\", \"ServerName\",\n    \"EchoServer\", \"BroadcastingEchoServer\", \"UpgradeSync\", \"UpgradeAsync\", \"ParameterRoutes\"};\n\n    strcat(CXXFLAGS, \" -march=native -O3 -Wpedantic -Wall -Wextra -Wsign-conversion -Wconversion -std=c++2b -Isrc -IuSockets/src\");\n    strcat(LDFLAGS, \" uSockets/*.o\");\n\n    // We can use libdeflate as a fast path to zlib (you need to build it first)\n    if (env_is(\"WITH_LIBDEFLATE\", \"1\")) {\n        strcat(LDFLAGS, \" libdeflate/libdeflate.a\");\n        strcat(CXXFLAGS, \" -DUWS_USE_LIBDEFLATE -I libdeflate\");\n    }\n\n    // By default we use LTO, but Windows does not support it\n    if (!env_is(\"WITH_LTO\", \"0\")) {\n        strcat(CXXFLAGS, \" -flto=auto\");\n    }\n\n    // By default we use zlib but you can build without it (disables permessage-deflate)\n    if (!env_is(\"WITH_ZLIB\", \"0\")) {\n        strcat(LDFLAGS, \" -lz\");\n    } else {\n        strcat(CXXFLAGS, \" -DUWS_NO_ZLIB\");\n    }\n\n    // WITH_PROXY enables PROXY Protocol v2 support\n    if (env_is(\"WITH_PROXY\", \"1\")) {\n        strcat(CXXFLAGS, \" -DUWS_WITH_PROXY\");\n    }\n\n    // WITH_QUIC enables experimental Http3 examples\n    if (env_is(\"WITH_QUIC\", \"1\")) {\n        strcat(CXXFLAGS, \" -DLIBUS_USE_QUIC\");\n        strcat(LDFLAGS, \" -pthread -lz -lm uSockets/lsquic/src/liblsquic/liblsquic.a\");\n    }\n\n    // Heavily prefer boringssl over openssl\n    if (env_is(\"WITH_BORINGSSL\", \"1\")) {\n        strcat(CFLAGS, \" -I uSockets/boringssl/include -pthread -DLIBUS_USE_OPENSSL\");\n        strcat(LDFLAGS, \" -pthread uSockets/boringssl/build/ssl/libssl.a uSockets/boringssl/build/crypto/libcrypto.a\");\n    } else {\n        // WITH_OPENSSL=1 enables OpenSSL 1.1+ support\n        if (env_is(\"WITH_OPENSSL\", \"1\")) {\n            // With problems on macOS, make sure to pass needed LDFLAGS required to find these\n            strcat(LDFLAGS, \" -lssl -lcrypto\");\n        } else {\n            // WITH_WOLFSSL=1 enables WolfSSL 4.2.0 support (mutually exclusive with OpenSSL)\n            if (env_is(\"WITH_WOLFSSL\", \"1\")) {\n                strcat(LDFLAGS, \" -L/usr/local/lib -lwolfssl\");\n            }\n        }\n    }\n\n    // WITH_LIBUV=1 builds with libuv as event-loop\n    if (env_is(\"WITH_LIBUV\", \"1\")) {\n        strcat(LDFLAGS, \" -luv\");\n    }\n\n    // WITH_ASIO=1 builds with ASIO as event-loop\n    if (env_is(\"WITH_ASIO\", \"1\")) {\n        strcat(CXXFLAGS, \" -pthread\");\n        strcat(LDFLAGS, \" -lpthread\");\n    }\n\n    // WITH_ASAN builds with sanitizers\n    if (env_is(\"WITH_ASAN\", \"1\")) {\n        strcat(CXXFLAGS, \" -fsanitize=address -g\");\n        strcat(LDFLAGS, \" -lasan\");\n    }\n\n    if (!strcmp(argv[1], \"examples\")) {\n        #pragma omp parallel for\n        for (int i = 0; i < sizeof(EXAMPLE_FILES) / sizeof(char *); i++) {\n            if (run(\"%s %s examples/%s.cpp %s -o %s%s\", CXX, CXXFLAGS, EXAMPLE_FILES[i], LDFLAGS, EXAMPLE_FILES[i], EXEC_SUFFIX)) {\n                exit(-1);\n            }\n        }\n    } else if (!strcmp(argv[1], \"capi\")) {\n        printf(\"capi target does nothing yet\\n\");\n    } else if (!strcmp(argv[1], \"clean\")) {\n        printf(\"clean target does nothing yet\\n\");\n    } else if (!strcmp(argv[1], \"install\")) {\n        // install target is not even supposed to be cross platform\n        printf(\"install target does nothing yet\\n\");\n    } else if (!strcmp(argv[1], \"all\")) {\n        printf(\"all target does nothing yet\\n\");\n    }\n}\n"
  },
  {
    "path": "build.h",
    "content": "#define _CRT_SECURE_NO_WARNINGS\n#include <stdlib.h>\n#include <string.h>\n#include <stdio.h>\n#include <stdarg.h>\n\nint env_is(char *env, char *target) {\n    char *val = getenv(env);\n    return val && !strcmp(val, target);\n}\n\nchar *maybe(char *in) {\n    return in ? in : \"\";\n}\n\nchar *or_else(char *in, char *otherwise) {\n    return in ? in : otherwise;\n}\n\nint run(const char *cmd, ...) {\n    char buf[2048];\n    va_list args;\n    va_start(args, cmd);\n    vsprintf(buf, cmd, args);\n    va_end(args);\n    printf(\"--> %s\\n\\n\", buf);\n    return system(buf);\n}\n"
  },
  {
    "path": "cluster/README.md",
    "content": "# uWS Cluster\n"
  },
  {
    "path": "examples/Broadcast.cpp",
    "content": "/* We simply call the root header file \"App.h\", giving you uWS::App and uWS::SSLApp */\n#include \"App.h\"\n#include <time.h>\n#include <iostream>\n\n/* This is a simple WebSocket echo server example.\n * You may compile it with \"WITH_OPENSSL=1 make\" or with \"make\" */\n\nuWS::SSLApp *globalApp;\n\nint main() {\n    /* ws->getUserData returns one of these */\n    struct PerSocketData {\n        /* Fill with user data */\n    };\n\n    /* Keep in mind that uWS::SSLApp({options}) is the same as uWS::App() when compiled without SSL support.\n     * You may swap to using uWS:App() if you don't need SSL */\n    uWS::SSLApp app = uWS::SSLApp({\n        /* There are example certificates in uWebSockets.js repo */\n        .key_file_name = \"misc/key.pem\",\n        .cert_file_name = \"misc/cert.pem\",\n        .passphrase = \"1234\"\n    }).ws<PerSocketData>(\"/*\", {\n        /* Settings */\n        .compression = uWS::SHARED_COMPRESSOR,\n        .maxPayloadLength = 16 * 1024 * 1024,\n        .idleTimeout = 16,\n        .maxBackpressure = 1 * 1024 * 1024,\n        .closeOnBackpressureLimit = false,\n        .resetIdleTimeoutOnSend = false,\n        .sendPingsAutomatically = true,\n        /* Handlers */\n        .upgrade = nullptr,\n        .open = [](auto *ws) {\n            /* Open event here, you may access ws->getUserData() which points to a PerSocketData struct */\n            ws->subscribe(\"broadcast\");\n        },\n        .message = [](auto */*ws*/, std::string_view /*message*/, uWS::OpCode /*opCode*/) {\n\n        },\n        .drain = [](auto */*ws*/) {\n            /* Check ws->getBufferedAmount() here */\n        },\n        .ping = [](auto */*ws*/, std::string_view) {\n            /* Not implemented yet */\n        },\n        .pong = [](auto */*ws*/, std::string_view) {\n            /* Not implemented yet */\n        },\n        .close = [](auto */*ws*/, int /*code*/, std::string_view /*message*/) {\n            /* You may access ws->getUserData() here */\n        }\n    }).listen(9001, [](auto *listen_socket) {\n        if (listen_socket) {\n            std::cout << \"Listening on port \" << 9001 << std::endl;\n        }\n    });\n\n    struct us_loop_t *loop = (struct us_loop_t *) uWS::Loop::get();\n    struct us_timer_t *delayTimer = us_create_timer(loop, 0, 0);\n\n    // broadcast the unix time as millis every 8 millis\n    us_timer_set(delayTimer, [](struct us_timer_t */*t*/) {\n\n        struct timespec ts;\n        timespec_get(&ts, TIME_UTC);\n\n        int64_t millis = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;\n\n        //std::cout << \"Broadcasting timestamp: \" << millis << std::endl;\n\n        globalApp->publish(\"broadcast\", std::string_view((char *) &millis, sizeof(millis)), uWS::OpCode::BINARY, false);\n\n    }, 8, 8);\n\n    globalApp = &app;\n\n    app.run();\n}\n"
  },
  {
    "path": "examples/BroadcastingEchoServer.cpp",
    "content": "#include \"App.h\"\n\nstruct us_listen_socket_t *global_listen_socket;\n\nint main() {\n\n    /* ws->getUserData returns one of these */\n    struct PerSocketData {\n        /* Fill with user data */\n        std::vector<std::string> topics;\n        int nr = 0;\n    };\n\n    /* Keep in mind that uWS::SSLApp({options}) is the same as uWS::App() when compiled without SSL support.\n     * You may swap to using uWS:App() if you don't need SSL */\n    uWS::SSLApp *app = new uWS::SSLApp({\n        /* There are example certificates in uWebSockets.js repo */\n        .key_file_name = \"misc/key.pem\",\n        .cert_file_name = \"misc/cert.pem\",\n        .passphrase = \"1234\"\n    });\n    \n    app->ws<PerSocketData>(\"/*\", {\n        /* Settings */\n        .compression = uWS::DISABLED,\n        .maxPayloadLength = 16 * 1024 * 1024,\n        .idleTimeout = 60,\n        .maxBackpressure = 16 * 1024 * 1024,\n        .closeOnBackpressureLimit = false,\n        .resetIdleTimeoutOnSend = true,\n        .sendPingsAutomatically = false,\n        /* Handlers */\n        .upgrade = nullptr,\n        .open = [](auto *ws) {\n            /* Open event here, you may access ws->getUserData() which points to a PerSocketData struct */\n\n            PerSocketData *perSocketData = (PerSocketData *) ws->getUserData();\n\n            for (int i = 0; i < 32; i++) {\n                std::string topic = std::to_string((uintptr_t)ws) + \"-\" + std::to_string(i);\n                perSocketData->topics.push_back(topic);\n                ws->subscribe(topic);\n            }\n        },\n        .message = [&app](auto *ws, std::string_view message, uWS::OpCode opCode) {\n            PerSocketData *perSocketData = (PerSocketData *) ws->getUserData();\n\n            app->publish(perSocketData->topics[(size_t)(++perSocketData->nr % 32)], message, opCode);\n            ws->publish(perSocketData->topics[(size_t)(++perSocketData->nr % 32)], message, opCode);\n        },\n        .drain = [](auto */*ws*/) {\n            /* Check ws->getBufferedAmount() here */\n            //std::cout << \"drain\" << std::endl;\n        },\n        .ping = [](auto */*ws*/, std::string_view ) {\n            /* Not implemented yet */\n        },\n        .pong = [](auto */*ws*/, std::string_view ) {\n            /* Not implemented yet */\n        },\n        .close = [](auto */*ws*/, int /*code*/, std::string_view /*message*/) {\n            /* You may access ws->getUserData() here */\n        }\n    }).listen(9001, [](auto *listen_s) {\n        if (listen_s) {\n            std::cout << \"Listening on port \" << 9001 << std::endl;\n            //listen_socket = listen_s;\n        }\n    });\n    \n    app->run();\n\n    delete app;\n\n    uWS::Loop::get()->free();\n}\n"
  },
  {
    "path": "examples/CachingApp.cpp",
    "content": "#include \"App.h\"\n#include <iostream>\n\nint main() {\n    uWS::App app;\n\n    /* Regular, non-cached response */\n    app.get(\"/not-cached\", [](auto *res, auto */*req*/) {\n        res->end(\"Responding without a cache\");\n    }).get(\"/*\", [](auto *res, auto */*req*/) {\n        /* A cached response with 5 seconds of lifetime */\n        std::cout << \"Filling cache now\" << std::endl;\n        res->end(\"This is a response\");\n    }, 5).listen(8080, [](bool success) {\n        if (success) {\n            std::cout << \"Listening on port 8080\" << std::endl;\n        } else {\n            std::cerr << \"Failed to listen on port 8080\" << std::endl;\n        }\n    });\n\n    app.run();\n}\n"
  },
  {
    "path": "examples/Client.cpp",
    "content": "// This example is broken and doesn't do anything. It is a potential interface for a future potential client.\n// There is no client support implemented in the library. This example is a placeholder.\n\n#include \"ClientApp.h\"\n#include <iostream>\n\nint main() {\n    uWS::ClientApp app({\n        .open = [](/*auto *ws*/) {\n            std::cout << \"Hello and welcome to client\" << std::endl;\n        },\n        .message = [](/*auto *ws, auto message*/) {\n\n        },\n        .close = [](/*auto *ws*/) {\n            std::cout << \"bye\" << std::endl;\n        }\n    });\n    \n    app.connect(\"ws://localhost:3000\", \"protocol\");\n    \n    app.run();\n}\n"
  },
  {
    "path": "examples/Crc32.cpp",
    "content": "#include \"App.h\"\n\n/* This is a good example for testing and showing the POST requests.\n * Anything you post (either with content-length or using transfer-encoding: chunked) will\n * be hashed with crc32 and sent back in the response. This example also shows how to deal with\n * aborted requests. */\n\n/* curl -H \"Transfer-Encoding: chunked\" --data-binary @video.mp4 http://localhost:3000 */\n/* curl --data-binary @video.mp4 http://localhost:3000 */\n/* crc32 video.mp4 */\n\n/* Note that uWS::SSLApp({options}) is the same as uWS::App() when compiled without SSL support */\n\n#include <sstream>\n#include <cstdint>\n#include <cstddef>\n\nuint32_t crc32(const char *s, size_t n, uint32_t crc = 0xFFFFFFFF) {\n\n    for (size_t i = 0; i < n; i++) {\n        unsigned char ch = static_cast<unsigned char>(s[i]);\n        for (size_t j = 0; j < 8; j++) {\n            uint32_t b = (ch ^ crc) & 1;\n            crc >>= 1;\n            if (b) crc = crc ^ 0xEDB88320;\n            ch >>= 1;\n        }\n    }\n\n    return crc;\n}\n\nint main() {\n\n    uWS::SSLApp({\n      .key_file_name = \"misc/key.pem\",\n      .cert_file_name = \"misc/cert.pem\",\n      .passphrase = \"1234\"\n    }).post(\"/*\", [](auto *res, auto *req) {\n\n        /* Display the headers */\n        std::cout << \" --- \" << req->getUrl() << \" --- \" << std::endl;\n        for (auto [key, value] : *req) {\n            std::cout << key << \": \" << value << std::endl;\n        }\n\n        auto isAborted = std::make_shared<bool>(false);\n        uint32_t crc = 0xFFFFFFFF;\n        res->onData([res, isAborted, crc](std::string_view chunk, bool isFin) mutable {\n            if (chunk.length()) {\n                crc = crc32(chunk.data(), chunk.length(), crc);\n            }\n\n            if (isFin && !*isAborted) {\n                std::stringstream s;\n                s << std::hex << (~crc) << std::endl;\n                res->end(s.str());\n            }\n        });\n\n        res->onAborted([isAborted]() {\n            *isAborted = true;\n        });\n    }).listen(3000, [](auto *listen_socket) {\n        if (listen_socket) {\n            std::cerr << \"Listening on port \" << 3000 << std::endl;\n        }\n    }).run();\n\n    std::cout << \"Failed to listen on port 3000\" << std::endl;\n}\n"
  },
  {
    "path": "examples/EchoBody.cpp",
    "content": "#include \"App.h\"\n\n/* Takes any method and echoes back the sent body. Can be used to test compliance of HTTP spec. */\n/* This example is also a good benchmark for body echoing. */\n\nint main() {\n\n    uWS::App().get(\"/*\", [](auto *res, auto */*req*/) {\n        /* Technically the any route could be used likewise, but GET is optimized like this */\n        res->end();\n    }).any(\"/*\", [](auto *res, auto */*req*/) {\n        std::unique_ptr<std::string> buffer;\n        res->onData([res, buffer = std::move(buffer)](std::string_view chunk, bool isFin) mutable {\n            if (isFin) [[likely]] {\n                if (buffer.get()) [[unlikely]] {\n                    buffer->append(chunk);\n                    res->end(*buffer);\n                } else {\n                    res->end(chunk);\n                }\n            } else {\n                if (!buffer.get()) {\n                    buffer = std::make_unique<std::string>(chunk);\n                } else {\n                    buffer->append(chunk);\n                }\n            }\n        });\n\n        /* In this particular case we actually don't need to know this, as we only rely on RAII above. */\n        res->onAborted([]() {});\n    }).listen(3000, [](auto *listen_socket) {\n        if (listen_socket) {\n            std::cerr << \"Listening on port \" << 3000 << std::endl;\n        }\n    }).run();\n\n    std::cout << \"Failed to listen on port 3000\" << std::endl;\n}\n"
  },
  {
    "path": "examples/EchoServer.cpp",
    "content": "/* We simply call the root header file \"App.h\", giving you uWS::App and uWS::SSLApp */\n#include \"App.h\"\n\n/* This is a simple WebSocket echo server example.\n * You may compile it with \"WITH_OPENSSL=1 make\" or with \"make\" */\n\nint main() {\n    /* ws->getUserData returns one of these */\n    struct PerSocketData {\n        /* Fill with user data */\n    };\n\n    /* Keep in mind that uWS::SSLApp({options}) is the same as uWS::App() when compiled without SSL support.\n     * You may swap to using uWS:App() if you don't need SSL */\n    uWS::App({\n        /* There are example certificates in uWebSockets.js repo */\n        .key_file_name = \"misc/key.pem\",\n        .cert_file_name = \"misc/cert.pem\",\n        .passphrase = \"1234\"\n    }).ws<PerSocketData>(\"/*\", {\n        /* Settings */\n        .compression = uWS::CompressOptions(uWS::DEDICATED_COMPRESSOR | uWS::DEDICATED_DECOMPRESSOR),\n        .maxPayloadLength = 100 * 1024 * 1024,\n        .idleTimeout = 16,\n        .maxBackpressure = 100 * 1024 * 1024,\n        .closeOnBackpressureLimit = false,\n        .resetIdleTimeoutOnSend = false,\n        .sendPingsAutomatically = true,\n        /* Handlers */\n        .upgrade = nullptr,\n        .open = [](auto */*ws*/) {\n            /* Open event here, you may access ws->getUserData() which points to a PerSocketData struct */\n\n        },\n        .message = [](auto *ws, std::string_view message, uWS::OpCode opCode) {\n            /* This is the opposite of what you probably want; compress if message is LARGER than 16 kb\n             * the reason we do the opposite here; compress if SMALLER than 16 kb is to allow for \n             * benchmarking of large message sending without compression */\n\n             /* Never mind, it changed back to never compressing for now */\n            ws->send(message, opCode, false);\n        },\n        .dropped = [](auto */*ws*/, std::string_view /*message*/, uWS::OpCode /*opCode*/) {\n            /* A message was dropped due to set maxBackpressure and closeOnBackpressureLimit limit */\n        },\n        .drain = [](auto */*ws*/) {\n            /* Check ws->getBufferedAmount() here */\n        },\n        .ping = [](auto */*ws*/, std::string_view) {\n            /* Not implemented yet */\n        },\n        .pong = [](auto */*ws*/, std::string_view) {\n            /* Not implemented yet */\n        },\n        .close = [](auto */*ws*/, int /*code*/, std::string_view /*message*/) {\n            /* You may access ws->getUserData() here */\n        }\n    }).listen(9001, [](auto *listen_socket) {\n        if (listen_socket) {\n            std::cout << \"Listening on port \" << 9001 << std::endl;\n        }\n    }).run();\n}\n"
  },
  {
    "path": "examples/EchoServerThreaded.cpp",
    "content": "#include \"App.h\"\n#include <thread>\n#include <algorithm>\n\nint main() {\n    /* ws->getUserData returns one of these */\n    struct PerSocketData {\n\n    };\n\n    /* Simple echo websocket server, using multiple threads */\n    std::vector<std::thread *> threads(std::thread::hardware_concurrency());\n\n    std::transform(threads.begin(), threads.end(), threads.begin(), [](std::thread */*t*/) {\n        return new std::thread([]() {\n\n            /* Very simple WebSocket echo server */\n            uWS::App().ws<PerSocketData>(\"/*\", {\n                /* Settings */\n                .compression = uWS::SHARED_COMPRESSOR,\n                .maxPayloadLength = 16 * 1024,\n                .idleTimeout = 10,\n                .maxBackpressure = 1 * 1024 * 1024,\n                /* Handlers */\n                .upgrade = nullptr,\n                .open = [](auto */*ws*/) {\n\n                },\n                .message = [](auto *ws, std::string_view message, uWS::OpCode opCode) {\n                    ws->send(message, opCode);\n                },\n                .drain = [](auto */*ws*/) {\n                    /* Check getBufferedAmount here */\n                },\n                .ping = [](auto */*ws*/, std::string_view) {\n\n                },\n                .pong = [](auto */*ws*/, std::string_view) {\n\n                },\n                .close = [](auto */*ws*/, int /*code*/, std::string_view /*message*/) {\n\n                }\n            }).listen(9001, [](auto *listen_socket) {\n                if (listen_socket) {\n                    std::cout << \"Thread \" << std::this_thread::get_id() << \" listening on port \" << 9001 << std::endl;\n                } else {\n                    std::cout << \"Thread \" << std::this_thread::get_id() << \" failed to listen on port 9001\" << std::endl;\n                }\n            }).run();\n\n        });\n    });\n\n    std::for_each(threads.begin(), threads.end(), [](std::thread *t) {\n        t->join();\n    });\n}\n"
  },
  {
    "path": "examples/HelloWorld.cpp",
    "content": "#include \"App.h\"\n\n/* Note that uWS::SSLApp({options}) is the same as uWS::App() when compiled without SSL support */\n\nint main() {\n    /* Overly simple hello world app */\n    uWS::SSLApp({\n      .key_file_name = \"misc/key.pem\",\n      .cert_file_name = \"misc/cert.pem\",\n      .passphrase = \"1234\"\n    }).get(\"/*\", [](auto *res, auto */*req*/) {\n        res->end(\"Hello world!\");\n    }).listen(3000, [](auto *listen_socket) {\n        if (listen_socket) {\n            std::cout << \"Listening on port \" << 3000 << std::endl;\n        }\n    }).run();\n\n    std::cout << \"Failed to listen on port 3000\" << std::endl;\n}\n"
  },
  {
    "path": "examples/HelloWorldThreaded.cpp",
    "content": "#include \"App.h\"\n#include \"LocalCluster.h\"\n\nint main() {\n    /* Note that SSL is disabled unless you build with WITH_OPENSSL=1 */\n    uWS::LocalCluster({\n        .key_file_name = \"misc/key.pem\",\n        .cert_file_name = \"misc/cert.pem\",\n        .passphrase = \"1234\"\n    },\n    [](uWS::SSLApp &app) {\n        /* Here this App instance is defined */\n        app.get(\"/*\", [](auto *res, auto * /*req*/) {\n            res->end(\"Hello world!\");\n        }).listen(3000, [](auto *listen_socket) {\n            if (listen_socket) {\n                /* Note that us_listen_socket_t is castable to us_socket_t */\n                std::cout << \"Thread \" << std::this_thread::get_id() << \" listening on port \" << us_socket_local_port(true, (struct us_socket_t *) listen_socket) << std::endl;\n            } else {\n                std::cout << \"Thread \" << std::this_thread::get_id() << \" failed to listen on port 3000\" << std::endl;\n            }\n        });\n    });\n}\n"
  },
  {
    "path": "examples/Http3Server.cpp",
    "content": "#ifdef LIBUS_USE_QUIC\n\n/* Do not rely on this API, it will change */\n#include \"Http3App.h\"\n#include <iostream>\n#include <fstream>\n\n/* This is an example serving a video over HTTP3, and echoing posted data back */\n/* Todo: use onWritable and tryEnd instead of end */\nint main() {\n\n    /* Read video file to memory */\n    std::ifstream file(\"video.mp4\", std::ios::binary | std::ios::ate);\n    std::streamsize size = file.tellg();\n    file.seekg(0, std::ios::beg);\n\n    std::vector<char> buffer(size);\n    if (!file.read(buffer.data(), size)) {\n        std::cout << \"Failed to load video.mp4\" << std::endl;\n        return 0;\n    }\n\n    /* We need a bootstrapping server that instructs\n     * the web browser to use HTTP3 */\n    (*new uWS::SSLApp({\n      .key_file_name = \"misc/key.pem\",\n      .cert_file_name = \"misc/cert.pem\",\n      .passphrase = \"1234\"\n    })).get(\"/*\", [&buffer](auto *res, auto *req) {\n        res->writeHeader(\"Alt-Svc\", \"h3=\\\":9004\\\"\");\n        res->writeHeader(\"Alternative-Protocol\", \"quic:9004\");\n        res->end(\"<html><h1>This is not HTTP3! Try refreshing (works in Firefox!)</h1></html>\");\n    }).listen(9004, [](auto *listen_socket) {\n        if (listen_socket) {\n            std::cout << \"Bootstrapping server Listening on port \" << 9004 << std::endl;\n        }\n    });\n\n    /* And we serve the video over HTTP3 */\n    uWS::H3App({\n      .key_file_name = \"misc/key.pem\",\n      .cert_file_name = \"misc/cert.pem\",\n      .passphrase = \"1234\"\n    }).get(\"/*\", [&buffer](auto *res, auto *req) {\n        res->end(\"<html><h1>Welcome to HTTP3! <a href=\\\"video.mp4\\\">Go see a movie</a></html></h1>\");\n    }).get(\"/video.mp4\", [&buffer](auto *res, auto *req) {\n        /* Send back a video */\n        res->end({&buffer[0], buffer.size()});\n    }).post(\"/*\", [](auto *res, auto *req) {\n\n        std::cout << \"Got POST request at \" << req->getHeader(\":path\") << std::endl;\n\n        /* You also need to set onAborted if receiving data */\n        res->onData([res, bodyBuffer = (std::string *)nullptr](std::string_view chunk, bool isLast) mutable {\n            if (isLast) {\n                std::cout << \"Sending back posted body now\" << std::endl;\n                if (bodyBuffer) {\n                    /* Send back the (chunked) body we got, as response */\n                    bodyBuffer->append(chunk);\n                    res->end(*bodyBuffer);\n                    delete bodyBuffer;\n                } else {\n                    /* Send back the body we got, as response (fast path) */\n                    res->end(chunk);\n                }\n            } else {\n                /* Slow path */\n                if (!bodyBuffer) {\n                    bodyBuffer = new std::string;\n                }\n                /* If we got the body in a chunk, buffer it up until whole */\n                bodyBuffer->append(chunk);\n            }\n\n        });\n\n        /* If you have pending, asynch work, you should abort such work in this callback */\n        res->onAborted([]() {\n            /* Again, just printing is not enough, you need to abort any pending work here\n             * so that nothing will call res->end, since the request was aborted and deleted */\n            printf(\"Stream was aborted!\\n\");\n        });\n    }).listen(9004, [](auto *listen_socket) {\n        if (listen_socket) {\n            std::cout << \"HTTP/3 server Listening on port \" << 9004 << std::endl;\n        }\n    }).run();\n\n    std::cout << \"Failed to listen on port 9004\" << std::endl;\n}\n\n#else\n\n#include <stdio.h>\n\nint main() {\n    printf(\"Compile with WITH_QUIC=1 WITH_BORINGSSL=1 make in order to build this example\\n\");\n}\n\n#endif"
  },
  {
    "path": "examples/HttpServer.cpp",
    "content": "/* This is a simple HTTP(S) web server much like Python's SimpleHTTPServer */\n\n#include <App.h>\n\n/* Helpers for this example */\n#include \"helpers/AsyncFileReader.h\"\n#include \"helpers/AsyncFileStreamer.h\"\n#include \"helpers/Middleware.h\"\n\n/* optparse */\n#define OPTPARSE_IMPLEMENTATION\n#include \"helpers/optparse.h\"\n\nint main(int argc, char **argv) {\n\n    int option;\n    struct optparse options;\n    optparse_init(&options, argv);\n\n    struct optparse_long longopts[] = {\n        {\"port\", 'p', OPTPARSE_REQUIRED},\n        {\"help\", 'h', OPTPARSE_NONE},\n        {\"passphrase\", 'a', OPTPARSE_REQUIRED},\n        {\"key\", 'k', OPTPARSE_REQUIRED},\n        {\"cert\", 'c', OPTPARSE_REQUIRED},\n        {\"dh_params\", 'd', OPTPARSE_REQUIRED},\n        {0}\n    };\n\n    int port = 3000;\n    uWS::SocketContextOptions ssl_options = {};\n\n    while ((option = optparse_long(&options, longopts, nullptr)) != -1) {\n        switch (option) {\n        case 'p':\n            port = atoi(options.optarg);\n            break;\n        case 'a':\n            ssl_options.passphrase = options.optarg;\n            break;\n        case 'c':\n            ssl_options.cert_file_name = options.optarg;\n            break;\n        case 'k':\n            ssl_options.key_file_name = options.optarg;\n            break;\n        case 'd':\n            ssl_options.dh_params_file_name = options.optarg;\n            break;\n        case 'h':\n        case '?':\n            fail:\n            std::cout << \"Usage: \" << argv[0] << \" [--help] [--port <port>] [--key <ssl key>] [--cert <ssl cert>] [--passphrase <ssl key passphrase>] [--dh_params <ssl dh params file>] <public root>\" << std::endl;\n            return 0;\n        }\n    }\n\n    char *root = optparse_arg(&options);\n    if (!root) {\n        goto fail;\n    }\n\n    AsyncFileStreamer asyncFileStreamer(root);\n\n    /* Either serve over HTTP or HTTPS */\n    uWS::SocketContextOptions empty_ssl_options = {};\n    if (memcmp(&ssl_options, &empty_ssl_options, sizeof(empty_ssl_options))) {\n        /* HTTPS */\n        uWS::SSLApp(ssl_options).get(\"/*\", [&asyncFileStreamer](auto *res, auto *req) {\n            serveFile(res, req);\n            asyncFileStreamer.streamFile(res, req->getUrl());\n        }).listen(port, [port, root](auto *token) {\n            if (token) {\n                std::cout << \"Serving \" << root << \" over HTTPS a \" << port << std::endl;\n            }\n        }).run();\n    } else {\n        /* HTTP */\n        uWS::App().get(\"/*\", [&asyncFileStreamer](auto *res, auto *req) {\n            serveFile(res, req);\n            asyncFileStreamer.streamFile(res, req->getUrl());\n        }).listen(port, [port, root](auto *token) {\n            if (token) {\n                std::cout << \"Serving \" << root << \" over HTTP a \" << port << std::endl;\n            }\n        }).run();\n    }\n\n    std::cout << \"Failed to listen to port \" << port << std::endl;\n}\n"
  },
  {
    "path": "examples/ParameterRoutes.cpp",
    "content": "#include \"App.h\"\n\n/* Note that uWS::SSLApp({options}) is the same as uWS::App() when compiled without SSL support */\n\nint main() {\n    /* Overly simple hello world app */\n    uWS::SSLApp({\n      .key_file_name = \"misc/key.pem\",\n      .cert_file_name = \"misc/cert.pem\",\n      .passphrase = \"1234\"\n    }).get(\"/:first/static/:second\", [](auto *res, auto *req) {\n\n        res->write(\"<h1>first is: \");\n        res->write(req->getParameter(\"first\"));\n        res->write(\"</h1>\");\n\n        res->write(\"<h1>second is: \");\n        res->write(req->getParameter(\"second\"));\n        res->end(\"</h1>\");\n\n    }).listen(3000, [](auto *listen_socket) {\n        if (listen_socket) {\n            std::cout << \"Listening on port \" << 3000 << std::endl;\n        }\n    }).run();\n\n    std::cout << \"Failed to listen on port 3000\" << std::endl;\n}\n"
  },
  {
    "path": "examples/Precompress.cpp",
    "content": "#include \"App.h\"\n\nint main() {\n    /* ws->getUserData returns one of these */\n    struct PerSocketData {\n        /* Fill with user data */\n    };\n\n    /* Keeping track of last prepared message */\n    uWS::PreparedMessage preparedMessage;\n    std::mutex m;\n\n    /* For demo, we create a thread that will update the precompressed message every second */\n    std::thread t2([&m, &preparedMessage]() {\n        for (int counter = 1; true; counter++) {\n            m.lock();\n            std::string newMessage = \"Hello you are looking at message number \" + std::to_string(counter) + \" and this text should be precompressed\";        \n            \n            /* Here the current preparedMessage is updated */\n            preparedMessage = uWS::Loop::get()->prepareMessage(newMessage, uWS::OpCode::TEXT, true);\n            \n            m.unlock();\n            std::this_thread::sleep_for(std::chrono::milliseconds(500));\n        }\n    });\n\n    uWS::App app;\n\n    app.ws<PerSocketData>(\"/*\", {\n        /* You must only use SHARED_COMPRESSOR with precompression (can't use dedicated_compressor) */\n        .compression = uWS::CompressOptions(uWS::SHARED_COMPRESSOR | uWS::DEDICATED_DECOMPRESSOR),\n        /* Handlers */\n        .upgrade = nullptr,\n        .open = [](auto */*ws*/) {\n            /* Open event here, you may access ws->getUserData() which points to a PerSocketData struct */\n\n        },\n        .message = [&m, &preparedMessage, &app](auto *ws, std::string_view message, uWS::OpCode opCode) {\n\n            /* First respond by echoing what they send us, without compression */\n            ws->send(message, opCode, false);\n\n            /* Send last prepared message */\n            m.lock();\n            ws->sendPrepared(preparedMessage);\n\n            /* Using publish should also take preparedMessage */\n            ws->subscribe(\"test\");\n            app.publishPrepared(\"test\", preparedMessage);\n            ws->unsubscribe(\"test\");\n\n            m.unlock();\n        },\n        .dropped = [](auto */*ws*/, std::string_view /*message*/, uWS::OpCode /*opCode*/) {\n            /* A message was dropped due to set maxBackpressure and closeOnBackpressureLimit limit */\n        },\n        .drain = [](auto */*ws*/) {\n            /* Check ws->getBufferedAmount() here */\n        },\n        .ping = [](auto */*ws*/, std::string_view) {\n            /* Not implemented yet */\n        },\n        .pong = [](auto */*ws*/, std::string_view) {\n            /* Not implemented yet */\n        },\n        .close = [](auto */*ws*/, int /*code*/, std::string_view /*message*/) {\n            /* You may access ws->getUserData() here */\n        }\n    }).listen(9001, [&t2](auto *listen_socket) {\n        if (listen_socket) {\n            std::cout << \"Listening on port \" << 9001 << std::endl;\n        }\n    }).run();\n}\n"
  },
  {
    "path": "examples/README.md",
    "content": "# Examples\n\nMake sure to also check out the JavaScript examples, the TypeDoc documentation browser and the Discussions tab here on GitHub. Much of what is true for the Node.js addon is true also for the C++ library.\n"
  },
  {
    "path": "examples/SecureGzipFileServer.cpp",
    "content": "#include <iostream>\n#include <unordered_map>\n#include <mutex>\n#include <thread>\n#include <chrono>\n#include <filesystem>\n#include <fstream>\n#include <string>\n#include <cstdint>\n#include <cstring>\n#include \"App.h\"\n\n#ifndef UWS_NO_ZLIB\n#include <zlib.h>\n#endif\n\n#if defined(__linux__)\n#include <sys/inotify.h>\n#include <unistd.h>\n#endif\n\nint cooldown = 0; // Seconds to sleep after reloading files (Linux only)\n\n// Custom hasher for transparent lookup with std::string and std::string_view\nstruct StringViewHasher {\n    using is_transparent = void;\n    std::size_t operator()(const std::string& s) const { return std::hash<std::string_view>{}(s); }\n    std::size_t operator()(std::string_view s) const { return std::hash<std::string_view>{}(s); }\n};\n\n// Custom equality comparator for transparent lookup\nstruct StringViewEqual {\n    using is_transparent = void;\n    bool operator()(std::string_view lhs, std::string_view rhs) const { return lhs == rhs; }\n};\n\n// Global variables\nstd::unordered_map<std::string, std::pair<std::string, bool>, StringViewHasher, StringViewEqual> file_map;\nstd::mutex map_mutex;\n#if defined(__linux__)\nint inotify_fd;\n#endif\nunsigned long fileSizes = 0;\n\n// Loads file content; compresses with zlib if UWS_NO_ZLIB is not defined and compression is beneficial\nstd::pair<std::string, bool> load_file_content(const std::filesystem::path& path) {\n    std::ifstream file(path, std::ios::binary);\n    if (!file) {\n        std::cerr << \"Failed to open file: \" << path << std::endl;\n        return {\"\", false};\n    }\n    file.seekg(0, std::ios::end);\n    size_t size = file.tellg();\n    file.seekg(0, std::ios::beg);\n    std::string content(size, 0);\n    file.read(&content[0], size);\n\n#ifndef UWS_NO_ZLIB\n    z_stream zs = {};\n    if (deflateInit2(&zs, Z_BEST_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY) == Z_OK) {\n        zs.next_in = reinterpret_cast<Bytef*>(content.data());\n        zs.avail_in = content.size();\n        size_t bound = deflateBound(&zs, content.size());\n        std::string compressed(bound, 0);\n        zs.next_out = reinterpret_cast<Bytef*>(&compressed[0]);\n        zs.avail_out = bound;\n        int ret = deflate(&zs, Z_FINISH);\n        if (ret == Z_STREAM_END) {\n            size_t compressed_size = zs.total_out;\n            deflateEnd(&zs);\n            compressed.resize(compressed_size);\n            if (compressed_size < size) {\n                fileSizes += compressed_size;\n                return {compressed, true};\n            }\n        } else {\n            deflateEnd(&zs);\n        }\n    }\n#endif\n    fileSizes += size;\n    return {content, false};\n}\n\n// Loads all files from the root folder into the map; adds inotify watches on Linux if inotify_fd >= 0\nvoid load_files(const std::string& root, int inotify_fd = -1) {\n    fileSizes = 0;\n    std::unordered_map<std::string, std::pair<std::string, bool>, StringViewHasher, StringViewEqual> new_map;\n    for (const auto& entry : std::filesystem::recursive_directory_iterator(root)) {\n        if (entry.is_regular_file() && !entry.path().filename().string().starts_with(\".\")) {\n            std::string relative_path = \"/\" + std::filesystem::relative(entry.path(), root).generic_string();\n            auto [content, compressed] = load_file_content(entry.path());\n            new_map[relative_path] = {content, compressed};\n#if defined(__linux__)\n            if (inotify_fd >= 0) {\n                inotify_add_watch(inotify_fd, entry.path().c_str(), IN_MODIFY);\n            }\n#endif\n        } else if (entry.is_directory()) {\n#if defined(__linux__)\n            if (inotify_fd >= 0) {\n                inotify_add_watch(inotify_fd, entry.path().c_str(), IN_CREATE | IN_DELETE | IN_MOVE);\n            }\n#endif\n        }\n    }\n    {\n        std::lock_guard<std::mutex> lock(map_mutex);\n        file_map = std::move(new_map);\n        std::cout << \"Loaded \" << (fileSizes / 1024 / 1024) << \" MB of files into RAM\" << std::endl;\n    }\n}\n\n#if defined(__linux__)\n// Background thread to monitor inotify events and reload files on changes (Linux only)\nvoid inotify_reloader_function(const std::string& root, int inotify_fd) {\n    char buffer[4096];\n    while (true) {\n        int length = read(inotify_fd, buffer, sizeof(buffer));\n        if (length < 0) {\n            std::cerr << \"Error reading inotify events: \" << strerror(errno) << std::endl;\n            break;\n        }\n        load_files(root, inotify_fd);\n        if (cooldown) {\n            std::cout << \"Sleeping for \" << cooldown << \" seconds after reload\" << std::endl;\n            std::this_thread::sleep_for(std::chrono::seconds(cooldown));\n        }\n    }\n}\n#endif\n\nint main(int argc, char** argv) {\n    if (argc != 3) {\n        std::cerr << \"Usage: \" << argv[0] << \" <root_folder> <cooldown>\" << std::endl;\n        return 1;\n    }\n    std::string root = argv[1];\n    cooldown = std::stoi(argv[2]);\n    if (cooldown < 0) {\n        std::cerr << \"Cooldown must be a non-negative integer\" << std::endl;\n        return 1;\n    }\n\n#if defined(__linux__)\n    inotify_fd = inotify_init();\n    if (inotify_fd < 0) {\n        std::cerr << \"Failed to initialize inotify: \" << strerror(errno) << std::endl;\n        return 1;\n    }\n    load_files(root, inotify_fd);\n    std::thread inotify_reloader(inotify_reloader_function, root, inotify_fd);\n#else\n    load_files(root); // Load once at startup on macOS and Windows\n#endif\n\n    uWS::App app;\n\n    // Static key for uWS handlers\n    static char handler_key;\n\n    // Add post and pre handlers to lock the mutex around event loop iterations\n    uWS::Loop::get()->addPostHandler(&handler_key, [](uWS::Loop* /*loop*/) {\n        std::lock_guard<std::mutex> lock(map_mutex);\n    });\n    uWS::Loop::get()->addPreHandler(&handler_key, [](uWS::Loop* /*loop*/) {\n        std::lock_guard<std::mutex> lock(map_mutex);\n    });\n\n    app.get(\"/\", [](auto* res, auto* req) {\n        auto it = file_map.find(std::string_view(\"/index.html\", 11));\n        if (it != file_map.end()) {\n            if (it->second.second) {\n                res->writeHeader(\"Content-Encoding\", \"gzip\");\n            }\n            res->end(it->second.first);\n        } else {\n            res->writeStatus(\"404 Not Found\");\n            res->end(\"Not Found\");\n        }\n    });\n\n    app.get(\"/*\", [](auto* res, auto* req) {\n        auto it = file_map.find(req->getUrl());\n        if (it != file_map.end()) {\n            if (it->second.second) {\n                res->writeHeader(\"Content-Encoding\", \"gzip\");\n            }\n            res->end(it->second.first);\n        } else {\n            res->writeStatus(\"404 Not Found\");\n            res->end(\"Not Found\");\n        }\n    });\n\n    app.listen(8000, [](auto* token) {\n        if (token) {\n            std::cout << \"Listening on port 8000\" << std::endl;\n        }\n    });\n\n    app.run();\n\n#if defined(__linux__)\n    inotify_reloader.join();\n    close(inotify_fd);\n#endif\n\n    return 0;\n}"
  },
  {
    "path": "examples/ServerName.cpp",
    "content": "#include \"App.h\"\n\n/* Note that uWS::SSLApp({options}) is the same as uWS::App() when compiled without SSL support */\n\nint main() {\n    /* The SSL context given in SSLApp constructor is the default / catch-all context */\n    uWS::SSLApp app = uWS::SSLApp({\n      .key_file_name = \"misc/key.pem\",\n      .cert_file_name = \"misc/cert.pem\",\n      .passphrase = \"1234\"\n    }).get(\"/*\", [](auto *res, auto */*req*/) {\n        res->end(\"Hello from catch-all context!\");\n    }).addServerName(\"*.google.*\", {\n      /* Following is the context for *.google.* domain */\n      .key_file_name = \"misc/key.pem\",\n      .cert_file_name = \"misc/cert.pem\",\n      .passphrase = \"1234\"\n    }).domain(\"*.google.*\").get(\"/*\", [](auto *res, auto */*req*/) {\n        res->end(\"Hello from *.google.* context!\");\n    }).listen(3000, [](auto *listenSocket) {\n        if (listenSocket) {\n            std::cout << \"Listening on port \" << 3000 << std::endl;\n        } else {\n            std::cout << \"Failed to listen on port 3000\" << std::endl;\n        }\n    }).run();\n}\n"
  },
  {
    "path": "examples/SmokeTest.cpp",
    "content": "#include \"App.h\"\n\n/* This is not an example; it is a smoke test used in CI testing */\n\nstruct Stream {\n    int offset;\n    bool aborted;\n};\n\nstd::string constantChunk;\n\nvoid streamData(auto *res, auto stream, int chunk) {\n\n  if (stream->aborted) {\n    return;\n  }\n\n  if (chunk < 1600) {\n    res->cork([res, stream, chunk]() {\n      auto ok = res->write(constantChunk);\n      if (ok) {\n        streamData(res, stream, chunk + 1);\n        return;\n      }\n\n      uWS::Loop::get()->defer([res, stream, chunk]() {\n        streamData(res, stream, chunk + 1);\n      });\n    });\n  } else {\n    res->cork([res]() {\n      res->end();\n    });\n  }\n}\n\nint main() {\n\n    for (int i = 0; i < 65536; i++) {\n        constantChunk.append(\"a\", 1);\n    }\n\n    uWS::SSLApp({\n      .key_file_name = \"misc/key.pem\",\n      .cert_file_name = \"misc/cert.pem\",\n      .passphrase = \"1234\"\n    }).get(\"/*\", [](auto *res, auto */*req*/) {\n\n        auto stream = std::make_shared<Stream>(0, false);\n        streamData(res, stream, 0);\n\n        res->onAborted([stream]() {\n            stream->aborted = true;\n        });\n    }).listen(3000, [](auto *listen_socket) {\n        if (listen_socket) {\n            std::cout << \"Listening on port \" << 3000 << std::endl;\n        }\n    }).run();\n\n    std::cout << \"Failed to listen on port 3000\" << std::endl;\n}\n"
  },
  {
    "path": "examples/UpgradeAsync.cpp",
    "content": "/* We simply call the root header file \"App.h\", giving you uWS::App and uWS::SSLApp */\n#include \"App.h\"\n\n/* This is a simple WebSocket \"async\" upgrade example.\n * You may compile it with \"WITH_OPENSSL=1 make\" or with \"make\" */\n\nint main() {\n    /* ws->getUserData returns one of these */\n    struct PerSocketData {\n        /* Define your user data */\n        int something;\n    };\n\n    /* Keep in mind that uWS::SSLApp({options}) is the same as uWS::App() when compiled without SSL support.\n     * You may swap to using uWS:App() if you don't need SSL */\n    uWS::SSLApp({\n        /* There are example certificates in uWebSockets.js repo */\n        .key_file_name = \"misc/key.pem\",\n        .cert_file_name = \"misc/cert.pem\",\n        .passphrase = \"1234\"\n    }).ws<PerSocketData>(\"/*\", {\n        /* Settings */\n        .compression = uWS::SHARED_COMPRESSOR,\n        .maxPayloadLength = 16 * 1024,\n        .idleTimeout = 10,\n        .maxBackpressure = 1 * 1024 * 1024,\n        /* Handlers */\n        .upgrade = [](auto *res, auto *req, auto *context) {\n\n            /* HttpRequest (req) is only valid in this very callback, so we must COPY the headers\n             * we need later on while upgrading to WebSocket. You must not access req after first return.\n             * Here we create a heap allocated struct holding everything we will need later on. */\n\n            struct UpgradeData {\n                std::string secWebSocketKey;\n                std::string secWebSocketProtocol;\n                std::string secWebSocketExtensions;\n                struct us_socket_context_t *context;\n                decltype(res) httpRes;\n                bool aborted = false;\n            } *upgradeData = new UpgradeData {\n                std::string(req->getHeader(\"sec-websocket-key\")),\n                std::string(req->getHeader(\"sec-websocket-protocol\")),\n                std::string(req->getHeader(\"sec-websocket-extensions\")),\n                context,\n                res\n            };\n\n            /* We have to attach an abort handler for us to be aware\n             * of disconnections while we perform async tasks */\n            res->onAborted([=]() {\n                /* We don't implement any kind of cancellation here,\n                 * so simply flag us as aborted */\n                upgradeData->aborted = true;\n                std::cout << \"HTTP socket was closed before we upgraded it!\" << std::endl;\n            });\n\n            /* Simulate checking auth for 5 seconds. This looks like crap, never write\n             * code that utilize us_timer_t like this; they are high-cost and should\n             * not be created and destroyed more than rarely!\n             *\n             * Also note that the code would be a lot simpler with capturing lambdas, maybe your\n             * database client has such a nice interface? Either way, here we go!*/\n            struct us_loop_t *loop = (struct us_loop_t *) uWS::Loop::get();\n            struct us_timer_t *delayTimer = us_create_timer(loop, 0, sizeof(UpgradeData *));\n            memcpy(us_timer_ext(delayTimer), &upgradeData, sizeof(UpgradeData *));\n            us_timer_set(delayTimer, [](struct us_timer_t *t) {\n                /* We wrote the upgradeData pointer to the timer's extension */\n                UpgradeData *upgradeData;\n                memcpy(&upgradeData, us_timer_ext(t), sizeof(UpgradeData *));\n\n                /* Were'nt we aborted before our async task finished? Okay, upgrade then! */\n                if (!upgradeData->aborted) {\n                    std::cout << \"Async task done, upgrading to WebSocket now!\" << std::endl;\n\n                    /* If you don't want to upgrade you can instead respond with custom HTTP here,\n                    * such as res->writeStatus(...)->writeHeader(...)->end(...); or similar.*/\n\n                    /* This call will immediately emit .open event */\n                    upgradeData->httpRes->cork([upgradeData]() {\n                        upgradeData->httpRes->template upgrade<PerSocketData>({\n                            /* We initialize PerSocketData struct here */\n                            .something = 13\n                        }, upgradeData->secWebSocketKey,\n                            upgradeData->secWebSocketProtocol,\n                            upgradeData->secWebSocketExtensions,\n                            upgradeData->context);\n                    });\n                } else {\n                    std::cout << \"Async task done, but the HTTP socket was closed. Skipping upgrade to WebSocket!\" << std::endl;\n                }\n\n                delete upgradeData;\n\n                us_timer_close(t);\n            }, 5000, 0);\n\n        },\n        .open = [](auto *ws) {\n            /* Open event here, you may access ws->getUserData() which points to a PerSocketData struct.\n             * Here we simply validate that indeed, something == 13 as set in upgrade handler. */\n            std::cout << \"Something is: \" << static_cast<PerSocketData *>(ws->getUserData())->something << std::endl;\n        },\n        .message = [](auto *ws, std::string_view message, uWS::OpCode opCode) {\n            /* We simply echo whatever data we get */\n            ws->send(message, opCode);\n        },\n        .drain = [](auto */*ws*/) {\n            /* Check ws->getBufferedAmount() here */\n        },\n        .ping = [](auto */*ws*/, std::string_view) {\n            /* You don't need to handle this one, we automatically respond to pings as per standard */\n        },\n        .pong = [](auto */*ws*/, std::string_view) {\n            /* You don't need to handle this one either */\n        },\n        .close = [](auto */*ws*/, int /*code*/, std::string_view /*message*/) {\n            /* You may access ws->getUserData() here, but sending or\n             * doing any kind of I/O with the socket is not valid. */\n        }\n    }).listen(9001, [](auto *listen_socket) {\n        if (listen_socket) {\n            std::cout << \"Listening on port \" << 9001 << std::endl;\n        }\n    }).run();\n}\n"
  },
  {
    "path": "examples/UpgradeSync.cpp",
    "content": "/* We simply call the root header file \"App.h\", giving you uWS::App and uWS::SSLApp */\n#include \"App.h\"\n\n/* This is a simple WebSocket \"sync\" upgrade example.\n * You may compile it with \"WITH_OPENSSL=1 make\" or with \"make\" */\n\nint main() {\n    /* ws->getUserData returns one of these */\n    struct PerSocketData {\n        /* Define your user data */\n        int something;\n    };\n\n    /* Keep in mind that uWS::SSLApp({options}) is the same as uWS::App() when compiled without SSL support.\n     * You may swap to using uWS:App() if you don't need SSL */\n    uWS::SSLApp({\n        /* There are example certificates in uWebSockets.js repo */\n        .key_file_name = \"misc/key.pem\",\n        .cert_file_name = \"misc/cert.pem\",\n        .passphrase = \"1234\"\n    }).ws<PerSocketData>(\"/*\", {\n        /* Settings */\n        .compression = uWS::SHARED_COMPRESSOR,\n        .maxPayloadLength = 16 * 1024,\n        .idleTimeout = 10,\n        .maxBackpressure = 1 * 1024 * 1024,\n        /* Handlers */\n        .upgrade = [](auto *res, auto *req, auto *context) {\n\n            /* You may read from req only here, and COPY whatever you need into your PerSocketData.\n             * PerSocketData is valid from .open to .close event, accessed with ws->getUserData().\n             * HttpRequest (req) is ONLY valid in this very callback, so any data you will need later\n             * has to be COPIED into PerSocketData here. */\n\n            /* Immediately upgrading without doing anything \"async\" before, is simple */\n            res->template upgrade<PerSocketData>({\n                /* We initialize PerSocketData struct here */\n                .something = 13\n            }, req->getHeader(\"sec-websocket-key\"),\n                req->getHeader(\"sec-websocket-protocol\"),\n                req->getHeader(\"sec-websocket-extensions\"),\n                context);\n\n            /* If you don't want to upgrade you can instead respond with custom HTTP here,\n             * such as res->writeStatus(...)->writeHeader(...)->end(...); or similar.*/\n\n            /* Performing async upgrade, such as checking with a database is a little more complex;\n             * see UpgradeAsync example instead. */\n        },\n        .open = [](auto *ws) {\n            /* Open event here, you may access ws->getUserData() which points to a PerSocketData struct.\n             * Here we simply validate that indeed, something == 13 as set in upgrade handler. */\n            std::cout << \"Something is: \" << static_cast<PerSocketData *>(ws->getUserData())->something << std::endl;\n        },\n        .message = [](auto *ws, std::string_view message, uWS::OpCode opCode) {\n            /* We simply echo whatever data we get */\n            ws->send(message, opCode);\n        },\n        .drain = [](auto */*ws*/) {\n            /* Check ws->getBufferedAmount() here */\n        },\n        .ping = [](auto */*ws*/, std::string_view) {\n            /* You don't need to handle this one, we automatically respond to pings as per standard */\n        },\n        .pong = [](auto */*ws*/, std::string_view) {\n            /* You don't need to handle this one either */\n        },\n        .close = [](auto */*ws*/, int /*code*/, std::string_view /*message*/) {\n            /* You may access ws->getUserData() here, but sending or\n             * doing any kind of I/O with the socket is not valid. */\n        }\n    }).listen(9001, [](auto *listen_socket) {\n        if (listen_socket) {\n            std::cout << \"Listening on port \" << 9001 << std::endl;\n        }\n    }).run();\n}\n"
  },
  {
    "path": "examples/helpers/AsyncFileReader.h",
    "content": "#include <map>\n#include <cstring>\n#include <fstream>\n#include <sstream>\n#include <iostream>\n#include <future>\n\n/* This is just a very simple and inefficient demo of async responses,\n * please do roll your own variant or use a database or Node.js's async\n * features instead of this really bad demo */\nstruct AsyncFileReader {\nprivate:\n    /* The cache we have in memory for this file */\n    std::string cache;\n    int cacheOffset;\n    bool hasCache;\n\n    /* The pending async file read (yes we only support one pending read) */\n    std::function<void(std::string_view)> pendingReadCb;\n\n    int fileSize;\n    std::string fileName;\n    std::ifstream fin;\n    uWS::Loop *loop;\n\npublic:\n    /* Construct a demo async. file reader for fileName */\n    AsyncFileReader(std::string fileName) : fileName(fileName) {\n        fin.open(fileName, std::ios::binary);\n\n        // get fileSize\n        fin.seekg(0, fin.end);\n        fileSize = fin.tellg();\n\n        //std::cout << \"File size is: \" << fileSize << std::endl;\n\n        // cache up 1 mb!\n        cache.resize(1024 * 1024);\n\n        //std::cout << \"Caching 1 MB at offset = \" << 0 << std::endl;\n        fin.seekg(0, fin.beg);\n        fin.read(cache.data(), cache.length());\n        cacheOffset = 0;\n        hasCache = true;\n\n        // get loop for thread\n\n        loop = uWS::Loop::get();\n    }\n\n    /* Returns any data already cached for this offset */\n    std::string_view peek(int offset) {\n        /* Did we hit the cache? */\n        if (hasCache && offset >= cacheOffset && ((offset - cacheOffset) < cache.length())) {\n            /* Cache hit */\n            //std::cout << \"Cache hit!\" << std::endl;\n\n            /*if (fileSize - offset < cache.length()) {\n                std::cout << \"LESS THAN WHAT WE HAVE!\" << std::endl;\n            }*/\n\n            int chunkSize = std::min<int>(fileSize - offset, cache.length() - offset + cacheOffset);\n\n            return std::string_view(cache.data() + offset - cacheOffset, chunkSize);\n        } else {\n            /* Cache miss */\n            //std::cout << \"Cache miss!\" << std::endl;\n            return std::string_view(nullptr, 0);\n        }\n    }\n\n    /* Asynchronously request more data at offset */\n    void request(int offset, std::function<void(std::string_view)> cb) {\n\n        // in this case, what do we do?\n        // we need to queue up this chunk request and callback!\n        // if queue is full, either block or close the connection via abort!\n        if (!hasCache) {\n            // already requesting a chunk!\n            std::cout << \"ERROR: already requesting a chunk!\" << std::endl;\n            return;\n        }\n\n        // disable cache\n        hasCache = false;\n\n        std::async(std::launch::async, [this, cb, offset]() {\n            //std::cout << \"ASYNC Caching 1 MB at offset = \" << offset << std::endl;\n\n\n\n            // den har stängts! öppna igen!\n            if (!fin.good()) {\n                fin.close();\n                //std::cout << \"Reopening fin!\" << std::endl;\n                fin.open(fileName, std::ios::binary);\n            }\n            fin.seekg(offset, fin.beg);\n            fin.read(cache.data(), cache.length());\n\n            cacheOffset = offset;\n\n            loop->defer([this, cb, offset]() {\n\n                int chunkSize = std::min<int>(cache.length(), fileSize - offset);\n\n                // båda dessa sker, wtf?\n                if (chunkSize == 0) {\n                    std::cout << \"Zero size!?\" << std::endl;\n                }\n\n                if (chunkSize != cache.length()) {\n                    std::cout << \"LESS THAN A CACHE 1 MB!\" << std::endl;\n                }\n\n                hasCache = true;\n                cb(std::string_view(cache.data(), chunkSize));\n            });\n        });\n    }\n\n    /* Abort any pending async. request */\n    void abort() {\n\n    }\n\n    int getFileSize() {\n        return fileSize;\n    }\n};\n"
  },
  {
    "path": "examples/helpers/AsyncFileStreamer.h",
    "content": "#include <filesystem>\n\nstruct AsyncFileStreamer {\n\n    std::map<std::string_view, AsyncFileReader *> asyncFileReaders;\n    std::string root;\n\n    AsyncFileStreamer(std::string root) : root(root) {\n        // for all files in this path, init the map of AsyncFileReaders\n        updateRootCache();\n    }\n\n    void updateRootCache() {\n        // todo: if the root folder changes, we want to reload the cache\n        for(auto &p : std::filesystem::recursive_directory_iterator(root)) {\n            std::string url = p.path().string().substr(root.length());\n            if (url == \"/index.html\") {\n                url = \"/\";\n            }\n\n            char *key = new char[url.length()];\n            memcpy(key, url.data(), url.length());\n            asyncFileReaders[std::string_view(key, url.length())] = new AsyncFileReader(p.path().string());\n        }\n    }\n\n    template <bool SSL>\n    void streamFile(uWS::HttpResponse<SSL> *res, std::string_view url) {\n        auto it = asyncFileReaders.find(url);\n        if (it == asyncFileReaders.end()) {\n            std::cout << \"Did not find file: \" << url << std::endl;\n        } else {\n            streamFile(res, it->second);\n        }\n    }\n\n    template <bool SSL>\n    static void streamFile(uWS::HttpResponse<SSL> *res, AsyncFileReader *asyncFileReader) {\n        /* Peek from cache */\n        std::string_view chunk = asyncFileReader->peek(res->getWriteOffset());\n        auto remaining_data = asyncFileReader->getFileSize() - res->getWriteOffset();\n        if (!chunk.length() || res->tryEnd(chunk, remaining_data).first) {\n            /* Request new chunk */\n            // todo: we need to abort this callback if peer closed!\n            // this also means Loop::defer needs to support aborting (functions should embedd an atomic boolean abort or something)\n\n            // Loop::defer(f) -> integer\n            // Loop::abort(integer)\n\n            // hmm? no?\n\n            // us_socket_up_ref eftersom vi delar ägandeskapet\n\n            if (chunk.length() < remaining_data) {\n                asyncFileReader->request(res->getWriteOffset(), [res, asyncFileReader](std::string_view chunk) {\n                    // check if we were closed in the mean time\n                    //if (us_socket_is_closed()) {\n                        // free it here\n                        //return;\n                    //}\n\n                    /* We were aborted for some reason */\n                    if (!chunk.length()) {\n                        // todo: make sure to check for is_closed internally after all callbacks!\n                        res->close();\n                    } else {\n                        AsyncFileStreamer::streamFile(res, asyncFileReader);\n                    }\n                });\n            }\n        } else {\n            /* We failed writing everything, so let's continue when we can */\n            res->onWritable([res, asyncFileReader](int offset) {\n\n                // här kan skiten avbrytas!\n\n                AsyncFileStreamer::streamFile(res, asyncFileReader);\n                // todo: I don't really know what this is supposed to mean?\n                return false;\n            })->onAborted([]() {\n                std::cout << \"ABORTED!\" << std::endl;\n            });\n        }\n    }\n};\n"
  },
  {
    "path": "examples/helpers/Middleware.h",
    "content": "/* Middleware to fill out content-type */\ninline bool hasExt(std::string_view file, std::string_view ext) {\n    if (ext.size() > file.size()) {\n        return false;\n    }\n    return std::equal(ext.rbegin(), ext.rend(), file.rbegin());\n}\n\n/* This should be a filter / middleware like app.use(handler) */\ntemplate <bool SSL>\nuWS::HttpResponse<SSL> *serveFile(uWS::HttpResponse<SSL> *res, uWS::HttpRequest *req) {\n    res->writeStatus(uWS::HTTP_200_OK);\n\n    if (hasExt(req->getUrl(), \".svg\")) {\n        res->writeHeader(\"Content-Type\", \"image/svg+xml\");\n    }\n\n    return res;\n}\n"
  },
  {
    "path": "examples/helpers/optparse.h",
    "content": "/* Nicked from third-party https://github.com/skeeto/optparse 2018-09-24 */\n/* µWebSockets is not the origin of this software file */\n/* ------------------------------------------------------ */\n\n/* Optparse --- portable, reentrant, embeddable, getopt-like option parser\n *\n * This is free and unencumbered software released into the public domain.\n *\n * To get the implementation, define OPTPARSE_IMPLEMENTATION.\n * Optionally define OPTPARSE_API to control the API's visibility\n * and/or linkage (static, __attribute__, __declspec).\n *\n * The POSIX getopt() option parser has three fatal flaws. These flaws\n * are solved by Optparse.\n *\n * 1) Parser state is stored entirely in global variables, some of\n * which are static and inaccessible. This means only one thread can\n * use getopt(). It also means it's not possible to recursively parse\n * nested sub-arguments while in the middle of argument parsing.\n * Optparse fixes this by storing all state on a local struct.\n *\n * 2) The POSIX standard provides no way to properly reset the parser.\n * This means for portable code that getopt() is only good for one\n * run, over one argv with one option string. It also means subcommand\n * options cannot be processed with getopt(). Most implementations\n * provide a method to reset the parser, but it's not portable.\n * Optparse provides an optparse_arg() function for stepping over\n * subcommands and continuing parsing of options with another option\n * string. The Optparse struct itself can be passed around to\n * subcommand handlers for additional subcommand option parsing. A\n * full reset can be achieved by with an additional optparse_init().\n *\n * 3) Error messages are printed to stderr. This can be disabled with\n * opterr, but the messages themselves are still inaccessible.\n * Optparse solves this by writing an error message in its errmsg\n * field. The downside to Optparse is that this error message will\n * always be in English rather than the current locale.\n *\n * Optparse should be familiar with anyone accustomed to getopt(), and\n * it could be a nearly drop-in replacement. The option string is the\n * same and the fields have the same names as the getopt() global\n * variables (optarg, optind, optopt).\n *\n * Optparse also supports GNU-style long options with optparse_long().\n * The interface is slightly different and simpler than getopt_long().\n *\n * By default, argv is permuted as it is parsed, moving non-option\n * arguments to the end. This can be disabled by setting the `permute`\n * field to 0 after initialization.\n */\n#ifndef OPTPARSE_H\n#define OPTPARSE_H\n\n#ifndef OPTPARSE_API\n#  define OPTPARSE_API\n#endif\n\nstruct optparse {\n    char **argv;\n    int permute;\n    int optind;\n    int optopt;\n    char *optarg;\n    char errmsg[64];\n    int subopt;\n};\n\nenum optparse_argtype {\n    OPTPARSE_NONE,\n    OPTPARSE_REQUIRED,\n    OPTPARSE_OPTIONAL\n};\n\nstruct optparse_long {\n    const char *longname;\n    int shortname;\n    enum optparse_argtype argtype;\n};\n\n/**\n * Initializes the parser state.\n */\nOPTPARSE_API\nvoid optparse_init(struct optparse *options, char **argv);\n\n/**\n * Read the next option in the argv array.\n * @param optstring a getopt()-formatted option string.\n * @return the next option character, -1 for done, or '?' for error\n *\n * Just like getopt(), a character followed by no colons means no\n * argument. One colon means the option has a required argument. Two\n * colons means the option takes an optional argument.\n */\nOPTPARSE_API\nint optparse(struct optparse *options, const char *optstring);\n\n/**\n * Handles GNU-style long options in addition to getopt() options.\n * This works a lot like GNU's getopt_long(). The last option in\n * longopts must be all zeros, marking the end of the array. The\n * longindex argument may be NULL.\n */\nOPTPARSE_API\nint optparse_long(struct optparse *options,\n                  const struct optparse_long *longopts,\n                  int *longindex);\n\n/**\n * Used for stepping over non-option arguments.\n * @return the next non-option argument, or NULL for no more arguments\n *\n * Argument parsing can continue with optparse() after using this\n * function. That would be used to parse the options for the\n * subcommand returned by optparse_arg(). This function allows you to\n * ignore the value of optind.\n */\nOPTPARSE_API\nchar *optparse_arg(struct optparse *options);\n\n/* Implementation */\n#ifdef OPTPARSE_IMPLEMENTATION\n\n#define OPTPARSE_MSG_INVALID \"invalid option\"\n#define OPTPARSE_MSG_MISSING \"option requires an argument\"\n#define OPTPARSE_MSG_TOOMANY \"option takes no arguments\"\n\nstatic int\noptparse_error(struct optparse *options, const char *msg, const char *data)\n{\n    unsigned p = 0;\n    const char *sep = \" -- '\";\n    while (*msg)\n        options->errmsg[p++] = *msg++;\n    while (*sep)\n        options->errmsg[p++] = *sep++;\n    while (p < sizeof(options->errmsg) - 2 && *data)\n        options->errmsg[p++] = *data++;\n    options->errmsg[p++] = '\\'';\n    options->errmsg[p++] = '\\0';\n    return '?';\n}\n\nOPTPARSE_API\nvoid\noptparse_init(struct optparse *options, char **argv)\n{\n    options->argv = argv;\n    options->permute = 1;\n    options->optind = 1;\n    options->subopt = 0;\n    options->optarg = 0;\n    options->errmsg[0] = '\\0';\n}\n\nstatic int\noptparse_is_dashdash(const char *arg)\n{\n    return arg != 0 && arg[0] == '-' && arg[1] == '-' && arg[2] == '\\0';\n}\n\nstatic int\noptparse_is_shortopt(const char *arg)\n{\n    return arg != 0 && arg[0] == '-' && arg[1] != '-' && arg[1] != '\\0';\n}\n\nstatic int\noptparse_is_longopt(const char *arg)\n{\n    return arg != 0 && arg[0] == '-' && arg[1] == '-' && arg[2] != '\\0';\n}\n\nstatic void\noptparse_permute(struct optparse *options, int index)\n{\n    char *nonoption = options->argv[index];\n    int i;\n    for (i = index; i < options->optind - 1; i++)\n        options->argv[i] = options->argv[i + 1];\n    options->argv[options->optind - 1] = nonoption;\n}\n\nstatic int\noptparse_argtype(const char *optstring, char c)\n{\n    int count = OPTPARSE_NONE;\n    if (c == ':')\n        return -1;\n    for (; *optstring && c != *optstring; optstring++);\n    if (!*optstring)\n        return -1;\n    if (optstring[1] == ':')\n        count += optstring[2] == ':' ? 2 : 1;\n    return count;\n}\n\nOPTPARSE_API\nint\noptparse(struct optparse *options, const char *optstring)\n{\n    int type;\n    char *next;\n    char *option = options->argv[options->optind];\n    options->errmsg[0] = '\\0';\n    options->optopt = 0;\n    options->optarg = 0;\n    if (option == 0) {\n        return -1;\n    } else if (optparse_is_dashdash(option)) {\n        options->optind++; /* consume \"--\" */\n        return -1;\n    } else if (!optparse_is_shortopt(option)) {\n        if (options->permute) {\n            int index = options->optind++;\n            int r = optparse(options, optstring);\n            optparse_permute(options, index);\n            options->optind--;\n            return r;\n        } else {\n            return -1;\n        }\n    }\n    option += options->subopt + 1;\n    options->optopt = option[0];\n    type = optparse_argtype(optstring, option[0]);\n    next = options->argv[options->optind + 1];\n    switch (type) {\n    case -1: {\n        char str[2] = {0, 0};\n        str[0] = option[0];\n        options->optind++;\n        return optparse_error(options, OPTPARSE_MSG_INVALID, str);\n    }\n    case OPTPARSE_NONE:\n        if (option[1]) {\n            options->subopt++;\n        } else {\n            options->subopt = 0;\n            options->optind++;\n        }\n        return option[0];\n    case OPTPARSE_REQUIRED:\n        options->subopt = 0;\n        options->optind++;\n        if (option[1]) {\n            options->optarg = option + 1;\n        } else if (next != 0) {\n            options->optarg = next;\n            options->optind++;\n        } else {\n            char str[2] = {0, 0};\n            str[0] = option[0];\n            options->optarg = 0;\n            return optparse_error(options, OPTPARSE_MSG_MISSING, str);\n        }\n        return option[0];\n    case OPTPARSE_OPTIONAL:\n        options->subopt = 0;\n        options->optind++;\n        if (option[1])\n            options->optarg = option + 1;\n        else\n            options->optarg = 0;\n        return option[0];\n    }\n    return 0;\n}\n\nOPTPARSE_API\nchar *\noptparse_arg(struct optparse *options)\n{\n    char *option = options->argv[options->optind];\n    options->subopt = 0;\n    if (option != 0)\n        options->optind++;\n    return option;\n}\n\nstatic int\noptparse_longopts_end(const struct optparse_long *longopts, int i)\n{\n    return !longopts[i].longname && !longopts[i].shortname;\n}\n\nstatic void\noptparse_from_long(const struct optparse_long *longopts, char *optstring)\n{\n    char *p = optstring;\n    int i;\n    for (i = 0; !optparse_longopts_end(longopts, i); i++) {\n        if (longopts[i].shortname) {\n            int a;\n            *p++ = longopts[i].shortname;\n            for (a = 0; a < (int)longopts[i].argtype; a++)\n                *p++ = ':';\n        }\n    }\n    *p = '\\0';\n}\n\n/* Unlike strcmp(), handles options containing \"=\". */\nstatic int\noptparse_longopts_match(const char *longname, const char *option)\n{\n    const char *a = option, *n = longname;\n    if (longname == 0)\n        return 0;\n    for (; *a && *n && *a != '='; a++, n++)\n        if (*a != *n)\n            return 0;\n    return *n == '\\0' && (*a == '\\0' || *a == '=');\n}\n\n/* Return the part after \"=\", or NULL. */\nstatic char *\noptparse_longopts_arg(char *option)\n{\n    for (; *option && *option != '='; option++);\n    if (*option == '=')\n        return option + 1;\n    else\n        return 0;\n}\n\nstatic int\noptparse_long_fallback(struct optparse *options,\n                       const struct optparse_long *longopts,\n                       int *longindex)\n{\n    int result;\n    char optstring[96 * 3 + 1]; /* 96 ASCII printable characters */\n    optparse_from_long(longopts, optstring);\n    result = optparse(options, optstring);\n    if (longindex != 0) {\n        *longindex = -1;\n        if (result != -1) {\n            int i;\n            for (i = 0; !optparse_longopts_end(longopts, i); i++)\n                if (longopts[i].shortname == options->optopt)\n                    *longindex = i;\n        }\n    }\n    return result;\n}\n\nOPTPARSE_API\nint\noptparse_long(struct optparse *options,\n              const struct optparse_long *longopts,\n              int *longindex)\n{\n    int i;\n    char *option = options->argv[options->optind];\n    if (option == 0) {\n        return -1;\n    } else if (optparse_is_dashdash(option)) {\n        options->optind++; /* consume \"--\" */\n        return -1;\n    } else if (optparse_is_shortopt(option)) {\n        return optparse_long_fallback(options, longopts, longindex);\n    } else if (!optparse_is_longopt(option)) {\n        if (options->permute) {\n            int index = options->optind++;\n            int r = optparse_long(options, longopts, longindex);\n            optparse_permute(options, index);\n            options->optind--;\n            return r;\n        } else {\n            return -1;\n        }\n    }\n\n    /* Parse as long option. */\n    options->errmsg[0] = '\\0';\n    options->optopt = 0;\n    options->optarg = 0;\n    option += 2; /* skip \"--\" */\n    options->optind++;\n    for (i = 0; !optparse_longopts_end(longopts, i); i++) {\n        const char *name = longopts[i].longname;\n        if (optparse_longopts_match(name, option)) {\n            char *arg;\n            if (longindex)\n                *longindex = i;\n            options->optopt = longopts[i].shortname;\n            arg = optparse_longopts_arg(option);\n            if (longopts[i].argtype == OPTPARSE_NONE && arg != 0) {\n                return optparse_error(options, OPTPARSE_MSG_TOOMANY, name);\n            } if (arg != 0) {\n                options->optarg = arg;\n            } else if (longopts[i].argtype == OPTPARSE_REQUIRED) {\n                options->optarg = options->argv[options->optind];\n                if (options->optarg == 0)\n                    return optparse_error(options, OPTPARSE_MSG_MISSING, name);\n                else\n                    options->optind++;\n            }\n            return options->optopt;\n        }\n    }\n    return optparse_error(options, OPTPARSE_MSG_INVALID, option);\n}\n\n#endif /* OPTPARSE_IMPLEMENTATION */\n#endif /* OPTPARSE_H */\n"
  },
  {
    "path": "fuzzing/AsyncEpollHelloWorld.cpp",
    "content": "/* We rely on wrapped syscalls */\n#include \"libEpollFuzzer/epoll_fuzzer.h\"\n\n#include \"App.h\"\n\n/* We keep this one for teardown later on */\nstruct us_listen_socket_t *listen_socket;\n\n/* This test is run by libEpollFuzzer */\nvoid test() {\n\n    {\n        /* Keep in mind that uWS::SSLApp({options}) is the same as uWS::App() when compiled without SSL support.\n        * You may swap to using uWS:App() if you don't need SSL */\n        auto app = uWS::App({\n            /* There are example certificates in uWebSockets.js repo */\n            .key_file_name = \"../misc/key.pem\",\n            .cert_file_name = \"../misc/cert.pem\",\n            .passphrase = \"1234\"\n        }).get(\"/*\", [](auto *res, auto *req) {\n            auto aborted = std::make_shared<bool>();\n            *aborted = false;\n            res->onAborted([aborted]() {\n                *aborted = true;\n            });\n\n            uWS::Loop::get()->defer([res, aborted]() {\n                if (!*aborted) {\n                    res->cork([res, aborted]() {\n                        // Todo: also test upgrade to websocket here\n                        res->end(\"Hello async!\");\n                    });\n                }\n            });\n        }).listen(9001, [](auto *listenSocket) {\n            listen_socket = listenSocket;\n        });\n\n        app.run();\n    }\n    uWS::Loop::get()->free();\n}\n\n/* Thus function should shutdown the event-loop and let the test fall through */\nvoid teardown() {\n\t/* If we are called twice there's a bug (it potentially could if\n\t * all open sockets cannot be error-closed in one epoll_wait call).\n\t * But we only allow 1k FDs and we have a buffer of 1024 from epoll_wait */\n\tif (!listen_socket) {\n\t\texit(-1);\n\t}\n\n\t/* We might have open sockets still, and these will be error-closed by epoll_wait */\n\t// us_socket_context_close - close all open sockets created with this socket context\n    if (listen_socket) {\n        us_listen_socket_close(0, listen_socket);\n        listen_socket = NULL;\n    }\n}\n"
  },
  {
    "path": "fuzzing/AsyncEpollHelloWorld.dict",
    "content": "\"get\"\n\"post\"\n\"get /\"\n\"http/1.1\"\n\"upgrade: websocket\"\n\"\\x0D\\x0A\"\n\"sec-websocket-key: dGhlIHNhbXBsZSBub25jZQ==\"\n\"sec-websocket-version: 13\"\n\"get / http/1.1\"\n\"sec-websocket-extensions: permessage-deflate\"\n\"sec-websocket-protocol: \"\n\" \""
  },
  {
    "path": "fuzzing/EpollEchoServer.cpp",
    "content": "/* We rely on wrapped syscalls */\n#include \"libEpollFuzzer/epoll_fuzzer.h\"\n\n#include \"App.h\"\n\n/* We keep this one for teardown later on */\nstruct us_listen_socket_t *listen_socket;\n\n/* This test is run by libEpollFuzzer */\nvoid test() {\n\n    struct PerSocketData {\n        int nothing;\n        std::shared_ptr<bool> valid;\n    };\n\n    /* First byte determines what compressor to use */\n    unsigned char compressorByte;\n    if (consume_byte(&compressorByte)) {\n        //uWS::Loop::get()->free();\n        return;\n    }\n\n    uWS::CompressOptions compressors[] = {\n        uWS::DISABLED,\n        uWS::SHARED_COMPRESSOR,\n        uWS::DEDICATED_COMPRESSOR_3KB,\n        uWS::DEDICATED_COMPRESSOR_4KB,\n        uWS::DEDICATED_COMPRESSOR_8KB,\n        uWS::DEDICATED_COMPRESSOR_16KB,\n        uWS::DEDICATED_COMPRESSOR_32KB,\n        uWS::DEDICATED_COMPRESSOR_64KB,\n        uWS::DEDICATED_COMPRESSOR_128KB,\n        uWS::DEDICATED_COMPRESSOR_256KB\n    };\n\n    uWS::CompressOptions compressor = compressors[compressorByte % 10];\n\n    {\n        auto app = uWS::App().ws<PerSocketData>(\"/broadcast\", {\n            /* Settings */\n            .compression = compressor,\n            /* We want this to be low so that we can hit it, yet bigger than 256 */\n            .maxPayloadLength = 300,\n            .idleTimeout = 12,\n            /* Handlers */\n            .open = [](auto *ws) {\n                /* Subscribe to anything */\n                ws->subscribe(/*req->getHeader(*/\"topic\"/*)*/);\n            },\n            .message = [](auto *ws, std::string_view message, uWS::OpCode opCode) {\n                if (message.length() && message[0] == 'C') {\n                    ws->close();\n                } else if (message.length() && message[0] == 'E') {\n                    ws->end(1006);\n                } else {\n                    /* Publish to topic sent by message */\n                    ws->publish(message, message, opCode, true);\n\n                    if (message.length() && message[0] == 'U') {\n                        ws->unsubscribe(message);\n                    }\n                }\n            },\n            .drain = [](auto *ws) {\n                /* Check getBufferedAmount here */\n            },\n            .ping = [](auto *ws, std::string_view) {\n\n            },\n            .pong = [](auto *ws, std::string_view) {\n\n            },\n            .close = [](auto *ws, int code, std::string_view message) {\n                /* Cause reported crash */\n                ws->close();\n            }\n        }).ws<PerSocketData>(\"/*\", {\n            /* Settings */\n            .compression = compressor,\n            /* We want this to be low so that we can hit it, yet bigger than 256 */\n            .maxPayloadLength = 300,\n            .idleTimeout = 12,\n            /* Handlers */\n            .open = [](auto *ws) {\n\n                ws->getUserData()->valid.reset(new bool{true});\n\n                //if (req->getHeader(\"close_me\").length()) {\n                //    ws->close();\n                //} else if (req->getHeader(\"end_me\").length()) {\n                //    ws->end(1006);\n                //}\n            },\n            .message = [](auto *ws, std::string_view message, uWS::OpCode opCode) {\n                if (message.length() > 300) {\n                    /* Inform the sanitizer of the fault */\n                    fprintf(stderr, \"Too long message passed\\n\");\n                    free((void *) -1);\n                }\n\n                if (message.length() && message[0] == 'C') {\n                    ws->close();\n                } else if (message.length() && message[0] == 'E') {\n                    ws->end(1006);\n                } else {\n                    ws->send(message, opCode, true);\n                }\n            },\n            .drain = [](auto *ws) {\n                /* Check getBufferedAmount here */\n            },\n            .ping = [](auto *ws, std::string_view) {\n                /* Here we test send and end while uncorked, by having them send from deferred */\n                PerSocketData *psd = (PerSocketData *) ws->getUserData();\n\n                uWS::Loop::get()->defer([ws, valid = psd->valid]() {\n                    if (*valid.get()) {\n                        /* We haven't been closed */\n                        ws->send(\"Hello!\", uWS::TEXT, false);\n                        ws->end(1000);\n                    }\n                });\n            },\n            .pong = [](auto *ws, std::string_view) {\n\n            },\n            .close = [](auto *ws, int code, std::string_view message) {\n                (*ws->getUserData()->valid.get()) = false;\n            }\n        }).listen(9001, [](us_listen_socket_t *listenSocket) {\n            listen_socket = listenSocket;\n        });\n\n        app.run();\n    }\n\n    uWS::Loop::get()->free();\n}\n\n/* Thus function should shutdown the event-loop and let the test fall through */\nvoid teardown() {\n\t/* If we are called twice there's a bug (it potentially could if\n\t * all open sockets cannot be error-closed in one epoll_wait call).\n\t * But we only allow 1k FDs and we have a buffer of 1024 from epoll_wait */\n\tif (!listen_socket) {\n\t\texit(-1);\n\t}\n\n\t/* We might have open sockets still, and these will be error-closed by epoll_wait */\n\t// us_socket_context_close - close all open sockets created with this socket context\n    if (listen_socket) {\n        us_listen_socket_close(0, listen_socket);\n        listen_socket = NULL;\n    }\n}\n"
  },
  {
    "path": "fuzzing/EpollEchoServer.dict",
    "content": "\"get\"\n\"post\"\n\"get /\"\n\"http/1.1\"\n\"upgrade: websocket\"\n\"\\x0D\\x0A\"\n\"sec-websocket-key: dGhlIHNhbXBsZSBub25jZQ==\"\n\"sec-websocket-version: 13\"\n\"get / http/1.1\"\n\"sec-websocket-extensions: permessage-deflate\"\n\"sec-websocket-protocol: \"\n\" \""
  },
  {
    "path": "fuzzing/EpollEchoServerPubSub.cpp",
    "content": "/* We rely on wrapped syscalls */\n#include \"libEpollFuzzer/epoll_fuzzer.h\"\n\n#include \"App.h\"\n#include <vector>\n\n/* We keep this one for teardown later on */\nstruct us_listen_socket_t *listen_socket;\n\n/* This test is run by libEpollFuzzer */\nvoid test() {\n\n    /* ws->getUserData returns one of these */\n    struct PerSocketData {\n        /* Fill with user data */\n        std::vector<std::string> topics;\n        int nr = 0;\n    };\n\n    /* Keep in mind that uWS::SSLApp({options}) is the same as uWS::App() when compiled without SSL support.\n     * You may swap to using uWS:App() if you don't need SSL */\n    uWS::SSLApp *app = new uWS::SSLApp({\n        /* There are example certificates in uWebSockets.js repo */\n\t    .key_file_name = \"../misc/key.pem\",\n\t    .cert_file_name = \"../misc/cert.pem\",\n\t    .passphrase = \"1234\"\n\t});\n    \n    app->ws<PerSocketData>(\"/*\", {\n        /* Settings */\n        .compression = uWS::DISABLED,\n        .maxPayloadLength = 512, // also have a low value here for fuzzing\n        .idleTimeout = 60,\n        .maxBackpressure = 128, // we want a low number so that we can reach this in fuzzing\n        .closeOnBackpressureLimit = false, // this one could be tested as well\n        .resetIdleTimeoutOnSend = true, // and this\n        .sendPingsAutomatically = false, // and this\n        /* Handlers */\n        .upgrade = nullptr,\n        .open = [](auto *ws) {\n            /* Open event here, you may access ws->getUserData() which points to a PerSocketData struct */\n\n            PerSocketData *perSocketData = (PerSocketData *) ws->getUserData();\n\n            for (int i = 0; i < 100; i++) {\n                std::string topic = std::to_string((uintptr_t)ws) + \"-\" + std::to_string(i);\n                perSocketData->topics.push_back(topic);\n                ws->subscribe(topic);\n            }\n        },\n        .message = [&app](auto *ws, std::string_view message, uWS::OpCode opCode) {\n            PerSocketData *perSocketData = (PerSocketData *) ws->getUserData();\n\n            app->publish(perSocketData->topics[++perSocketData->nr % 100], message, opCode);\n        },\n        .drain = [](auto */*ws*/) {\n            /* Check ws->getBufferedAmount() here */\n            //std::cout << \"drain\" << std::endl;\n        },\n        .ping = [](auto */*ws*/, std::string_view ) {\n            /* Not implemented yet */\n        },\n        .pong = [](auto */*ws*/, std::string_view ) {\n            /* Not implemented yet */\n        },\n        .close = [](auto */*ws*/, int /*code*/, std::string_view /*message*/) {\n            /* You may access ws->getUserData() here */\n        }\n    }).listen(9001, [](auto *listen_s) {\n        if (listen_s) {\n            //std::cout << \"Listening on port \" << 9001 << std::endl;\n            listen_socket = listen_s;\n        }\n    });\n    \n    app->run();\n\n    delete app;\n\n    uWS::Loop::get()->free();\n}\n\n/* Thus function should shutdown the event-loop and let the test fall through */\nvoid teardown() {\n\t/* If we are called twice there's a bug (it potentially could if\n\t * all open sockets cannot be error-closed in one epoll_wait call).\n\t * But we only allow 1k FDs and we have a buffer of 1024 from epoll_wait */\n\tif (!listen_socket) {\n\t\texit(-1);\n\t}\n\n\t/* We might have open sockets still, and these will be error-closed by epoll_wait */\n\t// us_socket_context_close - close all open sockets created with this socket context\n    if (listen_socket) {\n        us_listen_socket_close(0, listen_socket);\n        listen_socket = NULL;\n    }\n}\n"
  },
  {
    "path": "fuzzing/EpollEchoServerPubSub.dict",
    "content": "\"get\"\n\"post\"\n\"get /\"\n\"http/1.1\"\n\"upgrade: websocket\"\n\"\\x0D\\x0A\"\n\"sec-websocket-key: dGhlIHNhbXBsZSBub25jZQ==\"\n\"sec-websocket-version: 13\"\n\"get / http/1.1\"\n\"sec-websocket-extensions: permessage-deflate\"\n\"sec-websocket-protocol: \"\n\" \""
  },
  {
    "path": "fuzzing/EpollHelloWorld.cpp",
    "content": "/* We rely on wrapped syscalls */\n#include \"libEpollFuzzer/epoll_fuzzer.h\"\n\n#include \"App.h\"\n\n/* We keep this one for teardown later on */\nstruct us_listen_socket_t *listen_socket;\nstruct us_socket_t *client;\n\n/* This test is run by libEpollFuzzer */\nvoid test() {\n\t/* ws->getUserData returns one of these */\n    struct PerSocketData {\n        /* Fill with user data */\n    };\n\n    {\n        /* Keep in mind that uWS::SSLApp({options}) is the same as uWS::App() when compiled without SSL support.\n        * You may swap to using uWS:App() if you don't need SSL */\n        auto app = uWS::App({\n            /* There are example certificates in uWebSockets.js repo */\n            .key_file_name = \"../misc/key.pem\",\n            .cert_file_name = \"../misc/cert.pem\",\n            .passphrase = \"1234\"\n        }).ws<PerSocketData>(\"/empty\", {\n        /* Having no handlers here should not crash */\n        }).get(\"/*\", [](auto *res, auto *req) {\n            if (req->getHeader(\"write\").length()) {\n                res->writeStatus(\"200 OK\")->writeHeader(\"write\", \"true\")->write(\"Hello\");\n                res->write(\" world!\");\n                res->end();\n            } else if (req->getQuery().length()) {\n                res->close();\n            } else {\n                res->end(\"Hello world!\");\n            }\n        }).post(\"/*\", [](auto *res, auto *req) {\n            res->onAborted([]() {\n                /* We might as well use this opportunity to stress the loop a bit */\n                uWS::Loop::get()->defer([]() {\n\n                });\n            });\n            res->onData([res](std::string_view chunk, bool isEnd) {\n                if (isEnd) {\n                    res->cork([res, chunk]() {\n                        res->write(\"something ahead\");\n                        res->end(chunk);\n                    });\n                }\n            });\n        }).any(\"/:candy/*\", [](auto *res, auto *req) {\n            if (req->getParameter(0).length() == 0) {\n                free((void *) -1);\n            }\n            /* Some invalid queries */\n            req->getParameter(30000);\n            req->getParameter((unsigned short) -34234);\n            req->getHeader(\"yhello\");\n            req->getQuery();\n            req->getQuery(\"assd\");\n\n            res->end(\"done\");\n        }).ws<PerSocketData>(\"/*\", {\n            /* Settings */\n            .compression = uWS::SHARED_COMPRESSOR,\n            .maxPayloadLength = 16 * 1024,\n            .idleTimeout = 12,\n            .maxBackpressure = 1024,\n            /* Handlers */\n            .open = [](auto *ws) {\n                /* Open event here, you may access ws->getUserData() which points to a PerSocketData struct */\n                ws->getNativeHandle();\n                ws->getRemoteAddressAsText();\n                us_poll_ext((struct us_poll_t *) ws);\n            },\n            .message = [](auto *ws, std::string_view message, uWS::OpCode opCode) {\n                ws->send(message, opCode, true);\n            },\n            .drain = [](auto *ws) {\n                /* Check ws->getBufferedAmount() here */\n            },\n            .ping = [](auto *ws, std::string_view) {\n                /* We use this to trigger the async/wakeup feature */\n                uWS::Loop::get()->defer([]() {\n                    /* Do nothing */\n                });\n            },\n            .pong = [](auto *ws, std::string_view) {\n                /* Not implemented yet */\n            },\n            .close = [](auto *ws, int code, std::string_view message) {\n                /* You may access ws->getUserData() here */\n            }\n        }).listen(9001, [](auto *listenSocket) {\n            listen_socket = listenSocket;\n        });\n\n        /* Here we want to stress the connect feature, since nothing else stresses it */\n        struct us_loop_t *loop = (struct us_loop_t *) uWS::Loop::get();\n        /* This function is stupid */\n        us_loop_iteration_number(loop);\n        struct us_socket_context_t *client_context = us_create_socket_context(0, loop, 0, {});\n        us_socket_context_timestamp(0, client_context);\n        client = us_socket_context_connect(0, client_context, \"hostname\", 5000, \"localhost\", 0, 0);\n\t    \n        if (client) {\n            us_socket_is_established(0, client);\n            us_socket_local_port(0, client);\n        }\n\n        us_socket_context_on_connect_error(0, client_context, [](struct us_socket_t *s, int code) {\n            client = nullptr;\n            return s;\n        });\n\n        us_socket_context_on_open(0, client_context, [](struct us_socket_t *s, int is_client, char *ip, int ip_length) {\n            us_socket_flush(0, s);\n            return s;\n        });\n\n        us_socket_context_on_end(0, client_context, [](struct us_socket_t *s) {\n            /* Someone sent is a FIN, but we can still send data */\n            us_socket_write(0, s, \"asdadasdasdasdaddfgdfhdfgdfg\", 28, false);\n            return s;\n        });\n\n        us_socket_context_on_data(0, client_context, [](struct us_socket_t *s, char *data, int length) {\n            return s;\n        });\n\n        us_socket_context_on_writable(0, client_context, [](struct us_socket_t *s) {\n            /* Let's defer a close here */\n            us_socket_shutdown_read(0, s);\n            return s;\n        });\n\n        us_socket_context_on_close(0, client_context, [](struct us_socket_t *s, int code, void *reason) {\n            client = NULL;\n            return s;\n        });\n\n        /* Trigger some context functions */\n        app.addServerName(\"servername\", {});\n        app.removeServerName(\"servername\");\n        app.missingServerName(nullptr);\n        app.getNativeHandle();\n\n        app.run();\n\n        /* After done we also free the client context */\n        us_socket_context_free(0, client_context);\n    }\n    uWS::Loop::get()->setSilent(true);\n    uWS::Loop::get()->free();\n}\n\n/* Thus function should shutdown the event-loop and let the test fall through */\nvoid teardown() {\n\t/* If we are called twice there's a bug (it potentially could if\n\t * all open sockets cannot be error-closed in one epoll_wait call).\n\t * But we only allow 1k FDs and we have a buffer of 1024 from epoll_wait */\n\tif (!listen_socket && !client) {\n\t\texit(-1);\n\t}\n\n    if (client) {\n        us_socket_close(0, client, 0, 0);\n        client = NULL;\n    }\n\n\t/* We might have open sockets still, and these will be error-closed by epoll_wait */\n\t// us_socket_context_close - close all open sockets created with this socket context\n    if (listen_socket) {\n        us_listen_socket_close(0, listen_socket);\n        listen_socket = NULL;\n    }\n}\n"
  },
  {
    "path": "fuzzing/EpollHelloWorld.dict",
    "content": "\"get\"\n\"post\"\n\"get /\"\n\"http/1.1\"\n\"upgrade: websocket\"\n\"\\x0D\\x0A\"\n\"sec-websocket-key: dGhlIHNhbXBsZSBub25jZQ==\"\n\"sec-websocket-version: 13\"\n\"get / http/1.1\"\n\"sec-websocket-extensions: permessage-deflate\"\n\"sec-websocket-protocol: \"\n\" \""
  },
  {
    "path": "fuzzing/Extensions.cpp",
    "content": "/* This is a fuzz test of the websocket extensions parser */\n\n#define WIN32_EXPORT\n\n#include <cstdio>\n#include <string>\n#include <cstdlib>\n\n/* We test the websocket extensions parser */\n#include \"../src/WebSocketExtensions.h\"\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {\n\n    /* This one must not return shared compressor, or above 13 */\n    {\n        auto [negCompression, negCompressionWindow, negInflationWindow, response] = uWS::negotiateCompression(true, 13, 0, std::string_view((char *) data, size));\n\n        if (negCompression) {\n            /* If we want dedicated compression, we must not end up here! */\n            free((void *) (negCompressionWindow == 0));\n\n            /* Some more checks (freeing 0 does nothing) */\n            free((void *) (negCompressionWindow > 13));\n            free((void *) (negInflationWindow != 0));\n            free((void *) (negInflationWindow < 0 || negInflationWindow > 15 || negCompressionWindow < 0 || negCompressionWindow > 15));\n        }\n    }\n\n    /* This one must not return anything over 0 (only shared) */\n    {\n        auto [negCompression, negCompressionWindow, negInflationWindow, response] = uWS::negotiateCompression(true, 0, 0, std::string_view((char *) data, size));\n\n        if (negCompression) {\n            /* If we want shared compression, we must not end up here! */\n            free((void *) (negCompressionWindow != 0));\n        }\n    }\n\n\n    /* Whatever, this one must not negotiate anything */\n    {\n        auto [negCompression, negCompressionWindow, negInflationWindow, response] = uWS::negotiateCompression(false, 13, 15, std::string_view((char *) data, size));\n\n        if (negCompression) {\n            free((void *) -1);\n        }\n    }\n\n    return 0;\n}\n\n"
  },
  {
    "path": "fuzzing/Http.cpp",
    "content": "/* This is a fuzz test of the http parser */\n\n#define WIN32_EXPORT\n\n#include \"helpers.h\"\n\n/* We test the websocket parser */\n#include \"../src/HttpParser.h\"\n\n/* And the router */\n#include \"../src/HttpRouter.h\"\n\n/* Also ProxyParser */\n#include \"../src/ProxyParser.h\"\n\nstruct StaticData {\n\n    struct RouterData {\n\n    };\n\n    uWS::HttpRouter<RouterData> router;\n\n    StaticData() {\n\n        router.add({\"get\"}, \"/:hello/:hi\", [](auto *h) mutable {\n            auto [paramsTop, params] = h->getParameters();\n\n            /* Something is horribly wrong */\n            if (paramsTop != 1 || !params[0].length() || !params[1].length()) {\n                exit(-1);\n            }\n\n            /* This route did handle it */\n            return true;\n        });\n\n        router.add({\"post\"}, \"/:hello/:hi/*\", [](auto *h) mutable {\n            auto [paramsTop, params] = h->getParameters();\n\n            /* Something is horribly wrong */\n            if (paramsTop != 1 || !params[0].length() || !params[1].length()) {\n                exit(-1);\n            }\n\n            /* This route did handle it */\n            return true;\n        });\n\n        router.add({\"get\"}, \"/*\", [](auto *h) mutable {\n            auto [paramsTop, params] = h->getParameters();\n\n            /* Something is horribly wrong */\n            if (paramsTop != -1) {\n                exit(-1);\n            }\n\n            /* This route did not handle it */\n            return false;\n        });\n\n        router.add({\"get\"}, \"/hi\", [](auto *h) mutable {\n            auto [paramsTop, params] = h->getParameters();\n\n            /* Something is horribly wrong */\n            if (paramsTop != -1) {\n                exit(-1);\n            }\n\n            /* This route did handle it */\n            return true;\n        });\n    }\n} staticData;\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {\n    /* Create parser */\n    uWS::HttpParser httpParser;\n    /* User data */\n    void *user = (void *) 13;\n\n    /* If we are built with WITH_PROXY, pass a ProxyParser as reserved */\n    void *reserved = nullptr;\n#ifdef UWS_WITH_PROXY\n    uWS::ProxyParser pp;\n    reserved = (void *) &pp;\n#endif\n\n    /* Iterate the padded fuzz as chunks */\n    makeChunked(makePadded(data, size), size, [&httpParser, &user, reserved](const uint8_t *data, size_t size) {\n        /* We need at least 1 byte post padding */\n        if (size) {\n            size--;\n        } else {\n            /* We might be given zero length chunks */\n            return;\n        }\n\n        /* If user is null then ignore this chunk */\n        if (!user) {\n            return;\n        }\n\n        /* Parse it */\n        auto [err, returnedUser] = httpParser.consumePostPadded((char *) data, size, user, reserved, [reserved](void *s, uWS::HttpRequest *httpRequest) -> void * {\n\n            readBytes(httpRequest->getHeader(httpRequest->getUrl()));\n            readBytes(httpRequest->getMethod());\n            readBytes(httpRequest->getQuery());\n            readBytes(httpRequest->getQuery(\"hello\"));\n            readBytes(httpRequest->getQuery(\"\"));\n            //readBytes(httpRequest->getParameter(0));\n\n#ifdef UWS_WITH_PROXY\n            auto *pp = (uWS::ProxyParser *) reserved;\n            readBytes(pp->getSourceAddress());\n#endif\n\n            /* Route the method and URL in two passes */\n            staticData.router.getUserData() = {};\n            if (!staticData.router.route(httpRequest->getMethod(), httpRequest->getUrl())) {\n                /* It was not handled */\n                return nullptr;\n            }\n\n            for (auto p : *httpRequest) {\n\n            }\n\n            /* Return ok */\n            return s;\n\n        }, [](void *user, std::string_view data, bool fin) -> void * {\n\n            /* Return ok */\n            return user;\n\n        });\n\n        if (!returnedUser) {\n            /* It is of uttermost importance that if and when we return nullptr from the httpParser we must not\n             * ever use the httpParser ever again. It is in a broken state as returning nullptr is only used\n             * for signalling early closure. You must absolutely must throw it away. Here we just mark user as\n             * null so that we can ignore further chunks of data */\n            user = nullptr;\n        }\n    });\n\n    return 0;\n}\n\n"
  },
  {
    "path": "fuzzing/Makefile",
    "content": "# You can select which sanitizer to use by setting this\nSANITIZER ?= address\n# These are set by OSS-Fuzz, we default to AddressSanitizer\nCXXFLAGS ?= -DLIBUS_NO_SSL -fsanitize=$(SANITIZER),fuzzer\nCFLAGS ?= -DLIBUS_NO_SSL\nOUT ?= .\n\n# These are fetched from libEpollFuzzer\nWRAPPED_SYSCALLS = -Wl,--wrap=getpeername,--wrap=sendto,--wrap=send,--wrap=recv,--wrap=read,--wrap=listen,--wrap=getaddrinfo,--wrap=freeaddrinfo,--wrap=setsockopt,--wrap=fcntl,--wrap=bind,--wrap=socket,--wrap=epoll_wait,--wrap=epoll_create1,--wrap=timerfd_settime,--wrap=close,--wrap=accept4,--wrap=eventfd,--wrap=timerfd_create,--wrap=epoll_ctl,--wrap=shutdown\n\noss-fuzz:\n# Copy dictionaries\n\tcp *.dict $(OUT)\n# libEpollFuzzer cases\n\t# Compile uSockets without -flto\n\trm -rf *.o\n\t$(CC) $(CFLAGS) -DLIBUS_NO_SSL -std=c11 -I../uSockets/src -O3 -c ../uSockets/src/*.c ../uSockets/src/eventing/*.c ../uSockets/src/crypto/*.c\n\t# Link against object files\n\t$(CXX) $(CXXFLAGS) $(WRAPPED_SYSCALLS) -std=c++17 -O3 -DUWS_MOCK_ZLIB -I../src -I../uSockets/src EpollHelloWorld.cpp -o $(OUT)/EpollHelloWorld $(LIB_FUZZING_ENGINE) *.o\n\trm -f EpollHelloWorld.o\n\t$(CXX) $(CXXFLAGS) $(WRAPPED_SYSCALLS) -std=c++17 -O3 -DUWS_MOCK_ZLIB -I../src -I../uSockets/src AsyncEpollHelloWorld.cpp -o $(OUT)/AsyncEpollHelloWorld $(LIB_FUZZING_ENGINE) *.o\n\trm -f AsyncEpollHelloWorld.o\n\t$(CXX) $(CXXFLAGS) $(WRAPPED_SYSCALLS) -std=c++17 -O3 -DUWS_MOCK_ZLIB -I../src -I../uSockets/src EpollEchoServer.cpp -o $(OUT)/EpollEchoServer $(LIB_FUZZING_ENGINE) *.o\n\trm -f EpollEchoServer.o\n\t$(CXX) $(CXXFLAGS) $(WRAPPED_SYSCALLS) -std=c++17 -O3 -DUWS_MOCK_ZLIB -I../src -I../uSockets/src EpollEchoServerPubSub.cpp -o $(OUT)/EpollEchoServerPubSub $(LIB_FUZZING_ENGINE) *.o\n# \"Unit tests\"\n\t$(CXX) $(CXXFLAGS) -std=c++17 -O3 Extensions.cpp -o $(OUT)/Extensions $(LIB_FUZZING_ENGINE)\n\t$(CXX) $(CXXFLAGS) -std=c++17 -O3 QueryParser.cpp -o $(OUT)/QueryParser $(LIB_FUZZING_ENGINE)\n\t$(CXX) $(CXXFLAGS) -std=c++17 -O3 MultipartParser.cpp -o $(OUT)/MultipartParser $(LIB_FUZZING_ENGINE)\n\t$(CXX) $(CXXFLAGS) -std=c++17 -O3 -I../uSockets/src WebSocket.cpp -o $(OUT)/WebSocket $(LIB_FUZZING_ENGINE)\n\t$(CXX) $(CXXFLAGS) -std=c++17 -O3 Http.cpp -o $(OUT)/Http $(LIB_FUZZING_ENGINE)\n\t$(CXX) $(CXXFLAGS) -DUWS_WITH_PROXY -std=c++17 -O3 Http.cpp -o $(OUT)/HttpWithProxy $(LIB_FUZZING_ENGINE)\n\t$(CXX) $(CXXFLAGS) -DUWS_MOCK_ZLIB -std=c++17 -O3 PerMessageDeflate.cpp -o $(OUT)/PerMessageDeflate $(LIB_FUZZING_ENGINE)\n\t$(CXX) $(CXXFLAGS) -std=c++17 -O3 TopicTree.cpp -o $(OUT)/TopicTree $(LIB_FUZZING_ENGINE)\n\nregression_test:\n\t$(OUT)/EpollEchoServer seed-corpus/EpollEchoServer/regressions/*\n\t$(OUT)/EpollHelloWorld seed-corpus/EpollHelloWorld/regressions/*\n\t$(OUT)/EpollEchoServerPubSub seed-corpus/EpollEchoServerPubSub/regressions/*\n\t# $(OUT)/Extensions seed-corpus/Extensions/regressions/*\n\t# $(OUT)/QueryParser seed-corpus/QueryParser/regressions/*\n\t$(OUT)/TopicTree seed-corpus/TopicTree/regressions/*\n\t$(OUT)/WebSocket seed-corpus/WebSocket/regressions/*\n\t$(OUT)/Http seed-corpus/Http/regressions/*\n\t$(OUT)/HttpWithProxy seed-corpus/HttpWithProxy/regressions/*\n\t# $(OUT)/MultipartParser seed-corpus/MultipartParser/regressions/*\n\t$(OUT)/PerMessageDeflate seed-corpus/PerMessageDeflate/regressions/*\n"
  },
  {
    "path": "fuzzing/MultipartParser.cpp",
    "content": "/* This is a fuzz test of the multipart parser */\n\n#define WIN32_EXPORT\n\n#include <cstdio>\n#include <string>\n#include <cstdlib>\n\n#include \"../src/Multipart.h\"\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {\n\n    if (!size) {\n        return 0;\n    }\n\n    char *mutableMemory = (char *) malloc(size);\n    memcpy(mutableMemory, data, size);\n\n    /* First byte determines how long contentType is */\n    unsigned char contentTypeLength = data[0];\n    size--;\n\n    std::string_view contentType((char *) mutableMemory + 1, std::min<size_t>(contentTypeLength, size));\n    size -= contentType.length();\n\n    std::string_view body((char *) mutableMemory + 1 + contentType.length(), size);\n\n    uWS::MultipartParser mp(contentType);\n    if (mp.isValid()) {\n        mp.setBody(body);\n\n        std::pair<std::string_view, std::string_view> headers[10];\n\n        while (true) {\n            std::optional<std::string_view> optionalPart = mp.getNextPart(headers);\n            if (!optionalPart.has_value()) {\n                break;\n            }\n\n            std::string_view part = optionalPart.value();\n\n            for (int i = 0; headers[i].first.length(); i++) {\n                /* We care about content-type and content-disposition */\n                if (headers[i].first == \"content-disposition\") {\n                    /* Parse the parameters */\n                    uWS::ParameterParser pp(headers[i].second);\n                    while (true) {\n                        auto [key, value] = pp.getKeyValue();\n                        if (!key.length()) {\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    free(mutableMemory);\n    return 0;\n}\n\n"
  },
  {
    "path": "fuzzing/PerMessageDeflate.cpp",
    "content": "/* This is a fuzz test of the permessage-deflate module */\n\n#define WIN32_EXPORT\n\n#include <cstdio>\n#include <string>\n#include <bitset>\n\n/* We test the permessage deflate module */\n#include \"../src/PerMessageDeflate.h\"\n\n#include \"helpers.h\"\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {\n\n    /* First byte determines what compressor to use */\n    if (size >= 1) {\n\n        uWS::CompressOptions compressors[] = {\n            uWS::DEDICATED_COMPRESSOR_3KB,\n            uWS::DEDICATED_COMPRESSOR_4KB,\n            uWS::DEDICATED_COMPRESSOR_8KB,\n            uWS::DEDICATED_COMPRESSOR_16KB,\n            uWS::DEDICATED_COMPRESSOR_32KB,\n            uWS::DEDICATED_COMPRESSOR_64KB,\n            uWS::DEDICATED_COMPRESSOR_128KB,\n            uWS::DEDICATED_COMPRESSOR_256KB\n        };\n\n        auto compressor = compressors[data[0] % 8];\n        data++;\n        size--;\n\n        /* Bits 0 - 256 are okay */\n        std::bitset<257> b;\n\n        /* If we could specify LARGE_BUFFER_SIZE small here we could force it to inflate in chunks,\n        * triggering more line coverage. Currently it is set to 16kb which is always too much */\n        struct StaticData {\n            uWS::DeflationStream deflationStream;\n            uWS::InflationStream inflationStream;\n            uWS::ZlibContext zlibContext;\n        } staticData = {compressor, compressor};\n\n        /* Why is this padded? */\n        makeChunked(makePadded(data, size), size, [&staticData, &b](const uint8_t *data, size_t size) {\n            auto inflation = staticData.inflationStream.inflate(&staticData.zlibContext, std::string_view((char *) data, size), 256, true);\n\n            /* Trigger ASAN flaws if length is more than 256 */\n            if (inflation.has_value()) {\n                b.set(inflation->length());\n            }\n        });\n\n        makeChunked(makePadded(data, size), size, [&staticData](const uint8_t *data, size_t size) {\n            /* Always reset */\n            staticData.deflationStream.deflate(&staticData.zlibContext, std::string_view((char *) data, size), true);\n        });\n\n    }\n\n    return 0;\n}\n\n"
  },
  {
    "path": "fuzzing/QueryParser.cpp",
    "content": "#include \"../src/QueryParser.h\"\n\n#include <string>\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {\n\n    std::string modifiableInput((char *) data, size);\n\n    uWS::getDecodedQueryValue(\"\", modifiableInput);\n    uWS::getDecodedQueryValue(\"hello\", modifiableInput);\n\n    return 0;\n}"
  },
  {
    "path": "fuzzing/QueryParser.dict",
    "content": "\"?\"\n\"%FF\"\n\"&\"\n\"+\"\n\"hello\"\n\"=\"\n\n"
  },
  {
    "path": "fuzzing/README.md",
    "content": "# Fuzz-testing of various parsers, mocked examples and system libraries\n\nA secure web server must be capable of receiving mass amount of malicious input without misbehaving or performing illegal actions, such as stepping outside of a memory block or otherwise spilling the beans.\n\n### Continuous fuzzing under various sanitizers is done as part of the [Google OSS-Fuzz](https://github.com/google/oss-fuzz#oss-fuzz---continuous-fuzzing-for-open-source-software) project:\n* UndefinedBehaviorSanitizer\n* AddressSanitizer\n* MemorySanitizer\n\n### Overall coverage is about 95% for both uSockets and uWebSockets, all source code included\n* No defects or outstanding bugs\n* No timeouts, OOM, crashes or other issues\n* Transparent reporting of found issues: https://bugs.chromium.org/p/oss-fuzz/issues/list?q=label%3AProj-uwebsockets&can=1\n\n### Currently the following parts are individually fuzzed:\n\n* WebSocket handshake generator\n* WebSocket message parser\n* WebSocket extensions parser & negotiator\n* WebSocket permessage-deflate compression/inflation helper\n* Http parser (with and without Proxy Protocol v2)\n* Http method/url router\n* Pub/sub \"topic tree\"\n\n### While some targets are entire (mocked) example apps\n* libEpollFuzzer mocks the kernel syscalls and allows to cover a lot of uSockets source code.\n* A mock implementation of uSockets allows to cover a lot of the inbetween logic of uWebSockets.\n"
  },
  {
    "path": "fuzzing/TopicTree.cpp",
    "content": "#define WIN32_EXPORT\n\n#include \"helpers.h\"\n\n/* Test for the topic tree */\n#include \"../src/TopicTree.h\"\n\n#include <memory>\n\n// std::vector<std::string_view> topics = {\"\", \"one\", \"two\", \"three\"};\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {\n    /* Create topic tree */\n    uWS::TopicTree<std::string, std::string_view> topicTree([](uWS::Subscriber *s, std::string &message, auto flags) {\n\n        /* Depending on what publishing we do below (with or without empty strings),\n         * this assumption can hold true or not. For now it should hold true */\n        if (!message.length()) {\n            free((void *) -1);\n        }\n\n        /* Break if we have no subscriptions (not really an error, just to bring more randomness) */\n        if (s->topics.size() == 0) {\n            return true;\n        }\n\n        /* Success */\n        return false;\n    });\n\n    /* Holder for all manually allocated subscribers */\n    std::map<uint32_t, uWS::Subscriber *> subscribers;\n\n    /* Iterate the padded fuzz as chunks */\n    makeChunked(makePadded(data, size), size, [&topicTree, &subscribers](const uint8_t *data, size_t size) {\n        /* We need at least 5 bytes */\n        if (size > 4) {\n            /* Last of all is a string */\n            std::string_view lastString((char *) data + 5, size - 5);\n            \n            /* Why not */\n            topicTree.lookupTopic(lastString);\n\n            /* First 4 bytes is the subscriber id */\n            uint32_t id;\n            memcpy(&id, data, 4);\n\n            /* Then one byte action */\n            if (data[4] == 'S') {\n\n                /* Some ridiculously long topics has to be cut short (OOM) */\n                if (lastString.length() > 512) {\n                    lastString = \"too long!\";\n                }\n\n                /* Subscribe */\n                if (subscribers.find(id) == subscribers.end()) {\n\n                    /* Limit number of subscribers to 100 (OOM) */\n                    if (subscribers.size() > 100) {\n                        return;\n                    }\n\n                    uWS::Subscriber *subscriber = topicTree.createSubscriber();\n                    subscribers[id] = subscriber;\n                    topicTree.subscribe(subscriber, lastString);\n                } else {\n                    /* Limit per subscriber subscriptions (OOM) */\n                    uWS::Subscriber *subscriber = subscribers[id];\n                    if (subscriber->topics.size() < 50) {\n                        topicTree.subscribe(subscriber, lastString);\n                    }\n                }\n            } else if (data[4] == 'U') {\n                /* Unsubscribe */\n                auto it = subscribers.find(id);\n                if (it != subscribers.end()) {\n                    topicTree.unsubscribe(it->second, lastString);\n                }\n            } else if (data[4] == 'F') {\n                /* Free subscriber */\n                auto it = subscribers.find(id);\n                if (it != subscribers.end()) {\n                    topicTree.freeSubscriber(it->second);\n                    subscribers.erase(it);\n                }\n            } else if (data[4] == 'A') {\n                /* Unsubscribe from all */\n                auto it = subscribers.find(id);\n                if (it != subscribers.end()) {\n                    std::vector<std::string> topics;\n                    for (auto *topic : it->second->topics) {\n                        topics.push_back(topic->name);\n                    }\n\n                    for (std::string &topic : topics) {\n                        topicTree.unsubscribe(it->second, topic);\n                    }\n                }\n            } else if (data[4] == 'O') {\n                /* Drain one socket */\n                auto it = subscribers.find(id);\n                if (it != subscribers.end()) {\n                    topicTree.drain(it->second);\n                }\n            } else if (data[4] == 'P') {\n                /* Publish only if we actually have data */\n                if (lastString.length()) {\n                    topicTree.publish(nullptr, lastString, std::string(lastString));\n                } else {\n                    /* We could use having more strings */\n                    topicTree.publish(nullptr, \"\", \"anything\");\n                }\n            } else {\n                /* Drain for everything else (OOM) */\n                topicTree.drain();\n            }\n        }\n    });\n\n    /* Remove any subscriber from the tree */\n    for (auto &p : subscribers) {\n        topicTree.freeSubscriber(p.second);\n    }\n\n    return 0;\n}\n\n"
  },
  {
    "path": "fuzzing/TopicTree.dict",
    "content": "\"S\"\n\"P\"\n\"A\"\n\"U\"\n\"+\"\n\"/\"\n\"#\"\n\"\\x00\\x00\\x00\\x00\""
  },
  {
    "path": "fuzzing/WebSocket.cpp",
    "content": "/* This is a fuzz test of the websocket parser */\n\n#define WIN32_EXPORT\n\n#include \"helpers.h\"\n\n/* We test the websocket parser */\n#include \"../src/WebSocketProtocol.h\"\n\nstruct Impl {\n    static bool refusePayloadLength(uint64_t length, uWS::WebSocketState<true> *wState, void *s) {\n\n        /* We need a limit */\n        if (length > 16000) {\n            return true;\n        }\n\n        /* Return ok */\n        return false;\n    }\n\n    static bool setCompressed(uWS::WebSocketState<true> *wState, void *s) {\n        /* We support it */\n        return true;\n    }\n\n    static void forceClose(uWS::WebSocketState<true> *wState, void *s, std::string_view reason = {}) {\n\n    }\n\n    static bool handleFragment(char *data, size_t length, unsigned int remainingBytes, int opCode, bool fin, uWS::WebSocketState<true> *webSocketState, void *s) {\n\n        if (opCode == uWS::TEXT) {\n            if (!uWS::protocol::isValidUtf8((unsigned char *)data, length)) {\n                /* Return break */\n                return true;\n            }\n        } else if (opCode == uWS::CLOSE) {\n            uWS::protocol::parseClosePayload((char *)data, length);\n        }\n\n        /* Return ok */\n        return false;\n    }\n};\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {\n\n    /* Create the parser state */\n    uWS::WebSocketState<true> state;\n\n    makeChunked(makePadded(data, size), size, [&state](const uint8_t *data, size_t size) {\n        /* Parse it */\n        uWS::WebSocketProtocol<true, Impl>::consume((char *) data, size, &state, nullptr);\n    });\n\n    return 0;\n}\n\n"
  },
  {
    "path": "fuzzing/helpers.h",
    "content": "#ifndef HELPERS_H\n#define HELPERS_H\n\n/* Common helpers for fuzzing */\n\n#include <functional>\n#include <string_view>\n#include <cstring>\n\n/* We use this to pad the fuzz */\nstatic inline const uint8_t *makePadded(const uint8_t *data, size_t size) {\n    static int paddedLength = 512 * 1024;\n    static char *padded = new char[128 + paddedLength + 128];\n\n    /* Increase landing area if required */\n    if (paddedLength < size) {\n        delete [] padded;\n        paddedLength = size;\n        padded = new char [128 + paddedLength + 128];\n    }\n\n    memcpy(padded + 128, data, size);\n\n    return (uint8_t *) padded + 128;\n}\n\n/* Splits the fuzz data in one or many chunks */\nstatic inline void makeChunked(const uint8_t *data, size_t size, std::function<void(const uint8_t *data, size_t size)> cb) {\n    /* First byte determines chunk size; 0 is all that remains, 1-255 is small chunk */\n    for (int i = 0; i < size; ) {\n        unsigned int chunkSize = data[i++];\n        if (!chunkSize) {\n            chunkSize = size - i;\n        } else {\n            chunkSize = std::min<int>(chunkSize, size - i);\n        }\n\n        cb(data + i, chunkSize);\n        i += chunkSize;\n    }\n}\n\n/* Reads all bytes to trigger invalid reads */\nstatic inline void readBytes(std::string_view s) {\n    volatile int sum = 0;\n    for (int i = 0; i < s.size(); i++) {\n        sum += s[i];\n    }\n}\n\n#endif\n"
  },
  {
    "path": "libEpollBenchmarker/Makefile",
    "content": "# You need to link with wrapped syscalls\noverride CFLAGS += -Wl,--wrap=recv,--wrap=bind,--wrap=listen,--wrap=send,--wrap=socket,--wrap=epoll_wait,--wrap=accept4,--wrap=epoll_ctl\n\n# Include uSockets and uWebSockets\noverride CFLAGS += -DUWS_NO_ZLIB -I../src -I../uSockets/src\n\ndefault:\n\tmake -C ../uSockets\n\t$(CXX) -flto -O3 -std=c++17 ../examples/HelloWorld.cpp epoll_benchmarker.cpp $(CFLAGS) -o HelloWorld ../uSockets/uSockets.a\n"
  },
  {
    "path": "libEpollBenchmarker/epoll_benchmarker.cpp",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n#include <stdarg.h>\n\n#include <sys/timerfd.h>\n#include <sys/epoll.h>\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <netdb.h>\n#include <errno.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define NUM_SOCKETS 10\nuint64_t listen_socket_epoll_data = 0;\nepoll_event ready_events[NUM_SOCKETS] = {};\nstatic int accepted_sockets = 0;\n\nint __wrap_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) {\n\n\t// the listen socket\n\tif (fd == 500) {\n\t\tlisten_socket_epoll_data = event->data.u64;\n\t\treturn 0;\n\t} else {\n\t\tif (fd < 500) {\n\n\t\t} else {\n\t\t\t// on our FDs\n\t\t\tready_events[fd - 500 - 1].data.u64 = event->data.u64;\n\t\t\tready_events[fd - 500 - 1].events = EPOLLIN;\n\t\t}\n\t\t\n\t\treturn 0;\n\t}\n}\n\nint __wrap_epoll_wait(int epfd, struct epoll_event *events,\n               int maxevents, int timeout) {\n\n\tif (accepted_sockets != NUM_SOCKETS) {\n\t\tevents[0].events = EPOLLIN;\n\t\tevents[0].data.u64 = listen_socket_epoll_data;\n\t\treturn 1;\n\t} else {\n\t\tfor (int i = 0; i < NUM_SOCKETS; i++) {\n\t\t\tevents[i] = ready_events[i];\n\t\t}\n\t\treturn NUM_SOCKETS;\n\t}\n}\n\nint __wrap_recv(int sockfd, void *buf, size_t len, int flags) {\n\tconst char request[] =\n    \"GET /joyent/http-parser HTTP/1.1\\r\\n\"\n    \"Host: github.com\\r\\n\"\n    \"DNT: 1\\r\\n\"\n    \"Accept-Encoding: gzip, deflate, sdch\\r\\n\"\n    \"Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4\\r\\n\"\n    \"User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) \"\n        \"AppleWebKit/537.36 (KHTML, like Gecko) \"\n        \"Chrome/39.0.2171.65 Safari/537.36\\r\\n\"\n    \"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,\"\n        \"image/webp,*/*;q=0.8\\r\\n\"\n    \"Referer: https://github.com/joyent/http-parser\\r\\n\"\n    \"Connection: keep-alive\\r\\n\"\n    \"Cache-Control: max-age=0\\r\\n\\r\\n\";\n\n\tmemcpy(buf, request, sizeof(request) - 1);\n\treturn sizeof(request) - 1;\n}\n\nint __wrap_send(int sockfd, const void *buf, size_t len, int flags) {\n\tstatic int sent = 0;\n\tstatic clock_t lastTime = clock();\n\tif (++sent == 1000000) {\n\t\t// print how long it took to make 1 million requests\n\t\tclock_t newTime = clock();\n\t\tfloat elapsed = float(newTime - lastTime) / CLOCKS_PER_SEC;\n\t\tprintf(\"Req/sec: %f million\\n\", (1000000.0f / elapsed) / 1000000.0f);\n\t\tsent = 0;\n\t\tlastTime = newTime;\n\t}\n\n\treturn len;\n}\n\nint __wrap_bind() {\n\treturn 0;\n}\n\nint __wrap_setsockopt() {\n\treturn 0;\n}\n\nint __wrap_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {\n\tif (accepted_sockets < NUM_SOCKETS) {\n\t\taccepted_sockets++;\n\t\treturn accepted_sockets + 500;\n\t} else {\n\t\treturn -1;\n\t}\n}\n\nint __wrap_listen() {\n\treturn 0;\n}\n\nint __wrap_socket(int domain, int type, int protocol) {\n\treturn 500;\n}\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "misc/READMORE.md",
    "content": "# µWebSockets v19 user manual\n\nFor a list of frequently asked questions you may use the Discussions tab here on GitHub. Please don't misuse the issue tracker as your personal Q&A, we use it only for bug reporting. Discussions tab is less strict about content.\n\n## Motivation and goals\n\nµWebSockets is a simple to use yet thoroughly optimized, standards compliant and secure implementation of WebSockets (and HTTP).\nIt comes with built-in pub/sub support, URL routing, TLS 1.3, SNI, IPv6, permessage-deflate and is battle tested as one of the most popular implementations, reaching many millions of end-users daily. It's currently juggling billions of USD in many popular Bitcoin exchanges, every day with outstanding real-world performance.\n\n### Standards compliant\n\nUnlike other \"pub/sub brokers\", µWS does not assume or push any particular application protocol but only operates over raw, standard WebSockets. You need nothing but a standards compliant web browser and a handful of standards compliant JavaScript to communicate with it. No particular client library is needed or enforced - this unlike inadequate solutions like Socket.IO where you end up locked to a set of proprietary non-standard protocols with horrible performance.\n\n### Performant\nThe implementation is header-only C++17 (but examples use C++20 features for brevity and elegance!), cross-platform and compiles down to a tiny binary of a handful kilobytes.\nIt depends on µSockets, which is a standard C project for Linux, macOS & Windows.\n\nPerformance wise you can expect to outperform, or equal, just about anything similar out there, that's the fundamental goal of the project. I can show small-message cases where µWS **with SSL** significantly outperforms the fastest Golang servers running **non-SSL**. You get the SSL for free in a sense (shown to be true for messaging with up to 4 kB per message).\n\nWe've [openly presented](https://medium.com/swlh/100k-secure-websockets-with-raspberry-pi-4-1ba5d2127a23) detailed cases where a single Raspberry Pi 4 can serve more than 100k very active TLS 1.3 WebSockets, simultaneously, with excellent stability. This is entirely impossible with the vast majority of alternative solutions. Most solutions cramp up and become unreliable at a tiny fraction of this load, on such a limited hardware. We also have measurements where we [serve 12x the HTTP requests per second](https://levelup.gitconnected.com/serving-100k-requests-second-from-a-fanless-raspberry-pi-4-over-ethernet-fdd2c2e05a1e) as compared to Node.js.\n\n### Simple to use\nAnother goal of the project is minimalism, simplicity and elegance.\nDesign wise it follows an ExpressJS-like interface where you attach callbacks to different URL routes.\nThis way you can easily build complete REST/WebSocket services in a few lines of code.\n\nBoilerplate logic like heartbeat timeouts, backpressure handling, ping/pong and other annoyances are handled efficiently and easily by the library itself. You write business logic, the library handles the protocol(s).\n\nThe project is async only and runs local to one thread. You scale it as individual threads much like Node.js scales as individual processes. That is, the implementation only sees a single thread and is not thread-safe. There are simple ways to do threading via async delegates though, if you really need to.\n\n## Compiling\nµWebSockets is 100% standard header-only C++17 - it compiles on any platform. However, it depends on µSockets in all cases, which is platform-specific C code that runs on Linux, Windows and macOS.\n\nThere are a few compilation flags for µSockets (see its documentation), but common between µSockets and µWebSockets flags are as follows:\n\n* LIBUS_NO_SSL - disable OpenSSL dependency/functionality for uSockets and uWebSockets builds\n* UWS_NO_ZLIB - disable Zlib dependency/functionality for uWebSockets\n\nYou can use the Makefile on Linux and macOS. It is simple to use and builds the examples for you. `WITH_OPENSSL=1 make` builds all examples with SSL enabled. Examples will fail to listen if cert and key cannot be found, so make sure to specify a path that works for you.\n\n## User manual\n\n### uWS::App & uWS::SSLApp\nYou begin your journey by constructing an \"App\". Either an SSL-app or a regular TCP-only App. The uWS::SSLApp constructor takes a struct holding SSL options such as cert and key. Interfaces for both apps are identical, so let's call them both \"App\" from now on.\n\nApps follow the builder pattern, member functions return the App so that you can chain calls.\n\n### App.get, post, put, [...] and any routes\nYou attach behavior to \"URL routes\". A lambda is paired with a \"method\" (Http method that is) and a pattern (the URL matching pattern).\n\nMethods are many, but most common are probably get & post. They all have the same signature, let's look at one example:\n\n```c++\nuWS::App().get(\"/hello\", [](auto *res, auto *req) {\n    res->end(\"Hello World!\");\n});\n```\n\nImportant for all routes is that \"req\", the `uWS::HttpRequest *` dies with return. In other words, req is stack allocated so don't keep it in your pocket.\n\nres, the `uWS::HttpResponse<SSL> *` will be alive and accessible until either its .onAborted callback emits, or you've responded to the request via res.end or res.tryEnd.\n\nIn other words, you either respond to the request immediately and return, or you attach lambdas to the res (which may hold captured data), and respond later on in some other async callback.\n\nData that you capture in a res follows RAII and is move-only so you can properly move-in for instance std::string buffers that you may use to, for instance, buffer upp streaming POST data. It's pretty cool, check out mutable lambdas with move-only captures.\n\nThe \"any\" route will match any method.\n\n#### Pattern matching\nRoutes are matched in **order of specificity**, not by the order you register them:\n\n* Highest priority - static routes, think \"/hello/this/is/static\".\n* Middle priority - parameter routes, think \"/candy/:kind\", where value of :kind is retrieved by req.getParameter(0).\n* Lowest priority - wildcard routes, think \"/hello/*\".\n\nIn other words, the more specific a route is, the earlier it will match. This allows you to define wildcard routes that match a wide range of URLs and then \"carve\" out more specific behavior from that.\n\n\"Any\" routes, those who match any HTTP method, will match with lower priority than routes which specify their specific HTTP method (such as GET) if and only if the two routes otherwise are equally specific.\n\n#### Middlewares\nA very commonly asked question is how to achieve something like middlewares. We don't support middlewares as something built into the router itself. Partly because routes cannot pass data to other routes, partly because the HttpRequest object being stack-allocated and only valid in one single callback invocation, but most importantly - you can **easily** achieve the same function-chaining that is middlewares by instead using simple high-order functions and functional programming. There are tons of examples of this under Discussions (since it is a commonly asked question). A middleware isn't really something that has to be built-in to the server library itself, it really is just **a regular function**. By passing functions to other functions you can build chains of behaviors in very elegant and efficient ways.\n\nWhether this library should keep a set of commonly used functions is another question - we might do that in the future and we might add an example of its usage but right now there is nothing like this provided. We aim to provide an easy to use server implementation that you can build things on. Not complete business logic puzzle pieces.\n\n#### Streaming data\nYou should never call res.end(huge buffer). res.end guarantees sending so backpressure will probably spike. Instead you should use res.tryEnd to stream huge data part by part. Use in combination with res.onWritable and res.onAborted callbacks.\n\nTip: Check out the JavaScript project, it has many useful examples of async streaming of huge data.\n\n#### Corking\nIt is very important to understand the corking mechanism, as that is responsible for efficiently formatting, packing and sending data. Without corking your app will still work reliably, but can perform very bad and use excessive networking. In some cases the performance can be dreadful without proper corking.\n\nThat's why your sockets will be corked by default in most simple cases, including all of the examples provided. However there are cases where default corking cannot happen automatically.\n\n* Whenever your registered business logic (your callbacks) are called from the library, such as when receiving a message or when a socket opens, you'll be corked by default. Whatever you do with the socket inside of that callback will be efficient and properly corked.\n\n* If you have callbacks registered to some other library, say libhiredis, those callbacks will not be called with corked sockets (how could **we** know when to cork the socket if we don't control the third-party library!?).\n\n* Only one single socket can be corked at any point in time (isolated per thread, of course). It is efficient to cork-and-uncork.\n\n* Whenever your callback is a coroutine, such as the JavaScript async/await, automatic corking can only happen in the very first portion of the coroutine (consider await a separator which essentially cuts the coroutine into smaller segments). Only the first \"segment\" of the coroutine will be called from µWS, the following async segments will be called by the JavaScript runtime at a later point in time and will thus not be under our control with default corking enabled.\n\n* Corking is important even for calls which seem to be \"atomic\" and only send one chunk. res->end, res->tryEnd, res->writeStatus, res->writeHeader will most likely send multiple chunks of data and is very important to properly cork.\n\nYou can make sure corking is enabled, even for cases where default corking would be enabled, by wrapping whatever sending function calls in a lambda like so:\n\n```c++\nres->cork([res]() {\n    res->end(\"This Http response will be properly corked and efficient in all cases\");\n});\n```\n\nThe above res->end call will actually call three separate send functions; res->writeStatus, res->writeHeader and whatever it does itself. By wrapping the call in res->cork you make sure these three send functions are efficient and only result in one single send syscall and one single SSL block if using SSL.\n\nKeep this in mind, corking is by far the single most important performance trick to use. Even when streaming huge amounts of data it can be useful to cork. At least in the very tip of the response, as that holds the headers and status.\n\n### The App.ws route\nWebSocket \"routes\" are registered similarly, but not identically.\n\nEvery websocket route has the same pattern and pattern matching as for Http, but instead of one single callback you have a whole set of them, here's an example:\n\n```c++\nuWS::App().ws<PerSocketData>(\"/*\", {\n    /* Settings */\n    .compression = uWS::SHARED_COMPRESSOR,\n    .maxPayloadLength = 16 * 1024,\n    .idleTimeout = 10,\n    /* Handlers */\n    .upgrade = [](auto *res, auto *req, auto *context) {\n        /* You may read from req only here, and COPY whatever you need into your PerSocketData.\n         * See UpgradeSync and UpgradeAsync examples. */\n    },\n    .open = [](auto *ws) {\n\n    },\n    .message = [](auto *ws, std::string_view message, uWS::OpCode opCode) {\n        ws->send(message, opCode);\n    },\n    .drain = [](auto *ws) {\n        /* Check getBufferedAmount here */\n    },\n    .ping = [](auto *ws, std::string_view message) {\n\n    },\n    .pong = [](auto *ws, std::string_view message) {\n\n    },\n    .close = [](auto *ws, int code, std::string_view message) {\n\n    }\n});\n```\n\nWebSocket routes specify a user data type that should be used to keep per-websocket data. Many times people tend to attach user data\nwhich should belong to the websocket by putting the pointer and the user data in a std::map. That's wrong! Don't do that!\n\n#### Use the WebSocket.getUserData() feature\nYou should use the provided user data feature to store and attach any per-socket user data. Going from user data to WebSocket is possible if you make your user data hold a pointer to WebSocket, and hook things up in the WebSocket open handler. Your user data memory is valid while your WebSocket is.\n\nIf you want to create something more elaborate you could have the user data hold a pointer to some dynamically allocated memory block that keeps a boolean whether the WebSocket is still valid or not. Sky is the limit here, you should never need any std::map for this.\n\n#### WebSockets are valid from open to close\nAll given WebSocket pointers are guaranteed to live from open event (where you got your WebSocket) until close event is called. So is the user data memory. One open event will always end in exactly one close event, they are 1-to-1 and will always be balanced no matter what. Use them to drive your RAII data types, they can be seen as constructor and destructor.\n\nMessage events will never emit outside of open/close. Calling WebSocket.close or WebSocket.end will immediately call the close handler.\n\n#### Backpressure in websockets\nSimilarly to for Http, methods such as ws.send(...) can cause backpressure. Make sure to check ws.getBufferedAmount() before sending, and check the return value of ws.send before sending any more data. WebSockets do not have .onWritable, but instead make use of the .drain handler of the websocket route handler.\n\nInside of .drain event you should check ws.getBufferedAmount(), it might have drained, or even increased. Most likely drained but don't assume that it has, .drain event is only a hint that it has changed.\n\n#### Ping/pongs \"heartbeats\"\nThe library will automatically send pings to clients according to the `idleTimeout` specified. If you set idleTimeout = 120 seconds a ping will go out a few seconds before this timeout unless the client has sent something to the server recently. If the client responds to the ping, the socket will stay open. When client fails to respond in time, the socket will be forcefully closed and the close event will trigger. On disconnect all resources are freed, including subscriptions to topics and any backpressure. You can easily let the browser reconnect using 3-lines-or-so of JavaScript if you want to.\n\n#### Backpressure\nSending on a WebSocket can build backpressure. WebSocket::send returns an enum of BACKPRESSURE, SUCCESS or DROPPED. When send returns BACKPRESSURE it means you should stop sending data until the drain event fires and WebSocket::getBufferedAmount() returns a reasonable amount of bytes. But in case you specified a maxBackpressure when creating the WebSocketContext, this limit will automatically be enforced. That means an attempt at sending a message which would result in too much backpressure will be canceled and send will return DROPPED. This means the message was dropped and will not be put in the queue. maxBackpressure is an essential setting when using pub/sub as a slow receiver otherwise could build up a lot of backpressure. By setting maxBackpressure the library will automatically manage an enforce a maximum allowed backpressure per socket for you.\n\n#### Threading\nThe library is single threaded. You cannot, absolutely not, mix threads. A socket created from an App on thread 1 cannot be used in any way from thread 2. The only function in the whole entire library which is thread-safe and can be used from any thread is Loop:defer. Loop::defer takes a function (such as a lambda with data) and defers the execution of said function until the specified loop's thread is ready to execute the function in a single-threaded fashion on correct thread. So in case you want to publish a message under a topic, or send on some other thread's sockets you can, but it requires a bit of indirection. You should aim for having as isolated apps and threads as possible.\n\n#### Settings\nCompression (permessage-deflate) has three main modes; uWS::DISABLED, uWS::SHARED_COMPRESSOR and any of the uWS::DEDICATED_COMPRESSOR_xKB. Disabled and shared options require no memory, while dedicated compressor requires the amount of memory you selected. For instance, uWS::DEDICATED_COMPRESSOR_4KB adds an overhead of 4KB per WebSocket while uWS::DEDICATED_COMPRESSOR_256KB adds - you guessed it - 256KB!\n\nCompressing using shared means that every WebSocket message is an isolated compression stream, it does not have a sliding compression window, kept between multiple send calls like the dedicated variants do.\n\nYou probably want shared compressor if dealing with larger JSON messages, or 4kb dedicated compressor if dealing with smaller JSON messages and if doing binary messaging you probably want to disable it completely.\n\n* idleTimeout is roughly the amount of seconds that may pass between messages. Being idle for more than this, and the connection is severed. This means you should make your clients send small ping messages every now and then, to keep the connection alive. You can also make the server send ping messages but I would definitely put that labor on the client side. (outdated text - this is not entirely true anymore. The server will automatically send pings in case it needs to).\n\n### Listening on a port\nOnce you have defined your routes and their behavior, it is time to start listening for new connections. You do this by calling\n\n```c++\nApp.listen(port, [](auto *listenSocket) {\n    /* listenSocket is either nullptr or us_listen_socket */\n})\n```\n\nCanceling listening is done with the uSockets function call `us_listen_socket_close`.\n\n### App.run and fallthrough\nWhen you are done and want to enter the event loop, you call, once and only once, App.run.\nThis will block the calling thread until \"fallthrough\". The event loop will block until no more async work is scheduled, just like for Node.js.\n\nMany users ask how they should stop the event loop. That's not how it is done, you never stop it, you let it fall through. By closing all sockets, stopping the listen socket, removing any timers, etc, the loop will automatically cause App.run to return gracefully, with no memory leaks.\n\nBecause the App itself is under RAII control, once the blocking .run call returns and the App goes out of scope, all memory will gracefully be deleted.\n\n### Putting it all together\n\n```c++\nint main() {\n    uWS::App().get(\"/*\", [](auto *res, auto *req) {\n        res->end(\"Hello World!\");\n    }).listen(9001, [](auto *listenSocket) {\n        if (listenSocket) {\n            std::cout << \"Listening for connections...\" << std::endl;\n        }\n    }).run();\n\n    std::cout << \"Shoot! We failed to listen and the App fell through, exiting now!\" << std::endl;\n}\n```\n\n### Scaling up\n\nOne event-loop per thread, isolated and without shared data. That's the design here. Just like Node.js, but instead of per-process, it's per thread (well, obviously you can do it per-process also).\n\nIf you want to, you can simply take the previous example, put it inside of a few `std::thread` and listen to separate ports, or share the same port (works on Linux). More features like these will probably come, such as master/slave set-ups but it really isn't that hard to understand the concept - keep things isolated and spawn multiple instances of whatever code you have.\n\nRecent Node.js versions may scale using multiple threads, via the new Worker threads support. Scaling using that feature is identical to scaling using multiple threads in C++.\n\n### Compression\nWe aren't as careful with resources as we used to be. Just look at, how many web developers represent time - it is not uncommon for web developers to send an entire textual representation of time as 30-something actual letters inside a JSON document with an actual textual key. This is just awful. We have had standardized, time-zone neutral representation of time in binary, efficient, 4-byte (or more commonly the 8 byte variant) representation since the 1970s. It's called unix timestamp and is an elegant and efficient way of representing time-zone neutral time down to the seconds.\n\nThis is just an example of how we have regressed in our algorithmic thinking. Today it is common to use textual representations such as bloated JSON to represent data, even though most of that bloat is obvious repetitions and inefficient in nature. But we don't care because we have compression. True, even the most bloated source format can be compressed down to a small payload with few repetitions - however - this comes at TREMENDOUS cost.\n\nCompression should be seen as a last resort, a temporary duct-tape solution for when you cannot sit down and consider something better. Designing clever, binary and minimally repetitive protocols saves enormous amounts of CPU-time otherwise lost to compression.\n\nIn essence, compression is really just dynamically scanning for repetitions and gradually building up a dynamic palette of commonly repetitive chunks. That takes a lot of CPU-time and is incredibly inefficient. Overall, you're looking at only 20-30% remaining I/O performance if you use compression. Instead of letting some generic dynamic algorithm scan your inefficient data representation, you could have taken the time to design something that didn't suck in the first place.\n\nYou could have defined a static palette and referenced that efficiently using binary integers, instead of letting every single individual socket try and dynamically figure out and build that palette, dynamically and inefficiently, in its own memory consuming sliding window.\n\nProtoBuf and the like, where integral references can be used instead of textual strings is key if you plan on making something efficient. If you plan on using JSON that has to be compressed you might as well just shove your computer down a shredder and go do something else. That's my opinion and I have many of those.\n\nIt is true that we can do more permessage-deflate messages/second than many other solutions can do uncompressed messages/second, and yes we are entirely stable while doing so - but still - JSON is terrible.\n\nSo you might say - hey - that's too complex. Well build an SDK for your users then. Just wrap that \"complex\" protocol up in a JavaScript library that internally knows about this palette and exposes only simple-to-use functions for the end user. It's not that hard of a problem to solve.\n\n##### What about TLS/SSL then? I still have to encrypt!\nTLS is nothing like compression. With TLS 1.3 you're still looking at around 80% performance retention over non-TLS. This because TLS is block based and efficiently maps to modern CPUs. Modern CPUs also have hardware offloads for this. It's not that demanding to encrypt traffic using modern encryption standards. Compression is by far the most CPU-demanding thing you can do with your connection, and it requires TONS of per-socket memory.\n"
  },
  {
    "path": "misc/cert.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDXTCCAkWgAwIBAgIJAKLdQVPy90jjMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV\nBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX\naWRnaXRzIFB0eSBMdGQwHhcNMTkwMjAzMTQ0OTM1WhcNMjAwMjAzMTQ0OTM1WjBF\nMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50\nZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\nCgKCAQEA7i7IIEdICTiSTVx+ma6xHxOtcbd6wGW3nkxlCkJ1UuV8NmY5ovMsGnGD\nhJJtUQ2j5ig5BcJUf3tezqCNW4tKnSOgSISfEAKvpn2BPvaFq3yx2Yjz0ruvcGKp\nDMZBXmB/AAtGyN/UFXzkrcfppmLHJTaBYGG6KnmU43gPkSDy4iw46CJFUOupc51A\nFIz7RsE7mbT1plCM8e75gfqaZSn2k+Wmy+8n1HGyYHhVISRVvPqkS7gVLSVEdTea\nUtKP1Vx/818/HDWk3oIvDVWI9CFH73elNxBkMH5zArSNIBTehdnehyAevjY4RaC/\nkK8rslO3e4EtJ9SnA4swOjCiqAIQEwIDAQABo1AwTjAdBgNVHQ4EFgQUv5rc9Smm\n9c4YnNf3hR49t4rH4yswHwYDVR0jBBgwFoAUv5rc9Smm9c4YnNf3hR49t4rH4ysw\nDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEATcL9CAAXg0u//eYUAlQa\nL+l8yKHS1rsq1sdmx7pvsmfZ2g8ONQGfSF3TkzkI2OOnCBokeqAYuyT8awfdNUtE\nEHOihv4ZzhK2YZVuy0fHX2d4cCFeQpdxno7aN6B37qtsLIRZxkD8PU60Dfu9ea5F\nDDynnD0TUabna6a0iGn77yD8GPhjaJMOz3gMYjQFqsKL252isDVHEDbpVxIzxPmN\nw1+WK8zRNdunAcHikeoKCuAPvlZ83gDQHp07dYdbuZvHwGj0nfxBLc9qt90XsBtC\n4IYR7c/bcLMmKXYf0qoQ4OzngsnPI5M+v9QEHvYWaKVwFY4CTcSNJEwfXw+BAeO5\nOA==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "misc/key.pem",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDuLsggR0gJOJJN\nXH6ZrrEfE61xt3rAZbeeTGUKQnVS5Xw2Zjmi8ywacYOEkm1RDaPmKDkFwlR/e17O\noI1bi0qdI6BIhJ8QAq+mfYE+9oWrfLHZiPPSu69wYqkMxkFeYH8AC0bI39QVfOSt\nx+mmYsclNoFgYboqeZTjeA+RIPLiLDjoIkVQ66lznUAUjPtGwTuZtPWmUIzx7vmB\n+pplKfaT5abL7yfUcbJgeFUhJFW8+qRLuBUtJUR1N5pS0o/VXH/zXz8cNaTegi8N\nVYj0IUfvd6U3EGQwfnMCtI0gFN6F2d6HIB6+NjhFoL+QryuyU7d7gS0n1KcDizA6\nMKKoAhATAgMBAAECggEAd5g/3o1MK20fcP7PhsVDpHIR9faGCVNJto9vcI5cMMqP\n6xS7PgnSDFkRC6EmiLtLn8Z0k2K3YOeGfEP7lorDZVG9KoyE/doLbpK4MfBAwBG1\nj6AHpbmd5tVzQrnNmuDjBBelbDmPWVbD0EqAFI6mphXPMqD/hFJWIz1mu52Kt2s6\n++MkdqLO0ORDNhKmzu6SADQEcJ9Suhcmv8nccMmwCsIQAUrfg3qOyqU4//8QB8ZM\njosO3gMUesihVeuF5XpptFjrAliPgw9uIG0aQkhVbf/17qy0XRi8dkqXj3efxEDp\n1LSqZjBFiqJlFchbz19clwavMF/FhxHpKIhhmkkRSQKBgQD9blaWSg/2AGNhRfpX\nYq+6yKUkUD4jL7pmX1BVca6dXqILWtHl2afWeUorgv2QaK1/MJDH9Gz9Gu58hJb3\nymdeAISwPyHp8euyLIfiXSAi+ibKXkxkl1KQSweBM2oucnLsNne6Iv6QmXPpXtro\nnTMoGQDS7HVRy1on5NQLMPbUBQKBgQDwmN+um8F3CW6ZV1ZljJm7BFAgNyJ7m/5Q\nYUcOO5rFbNsHexStrx/h8jYnpdpIVlxACjh1xIyJ3lOCSAWfBWCS6KpgeO1Y484k\nEYhGjoUsKNQia8UWVt+uWnwjVSDhQjy5/pSH9xyFrUfDg8JnSlhsy0oC0C/PBjxn\nhxmADSLnNwKBgQD2A51USVMTKC9Q50BsgeU6+bmt9aNMPvHAnPf76d5q78l4IlKt\nwMs33QgOExuYirUZSgjRwknmrbUi9QckRbxwOSqVeMOwOWLm1GmYaXRf39u2CTI5\nV9gTMHJ5jnKd4gYDnaA99eiOcBhgS+9PbgKSAyuUlWwR2ciL/4uDzaVeDQKBgDym\nvRSeTRn99bSQMMZuuD5N6wkD/RxeCbEnpKrw2aZVN63eGCtkj0v9LCu4gptjseOu\n7+a4Qplqw3B/SXN5/otqPbEOKv8Shl/PT6RBv06PiFKZClkEU2T3iH27sws2EGru\nw3C3GaiVMxcVewdg1YOvh5vH8ZVlxApxIzuFlDvnAoGAN5w+gukxd5QnP/7hcLDZ\nF+vesAykJX71AuqFXB4Wh/qFY92CSm7ImexWA/L9z461+NKeJwb64Nc53z59oA10\n/3o2OcIe44kddZXQVP6KTZBd7ySVhbtOiK3/pCy+BQRsrC7d71W914DxNWadwZ+a\njtwwKjDzmPwdIXDSQarCx0U=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "src/App.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2020.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef UWS_APP_H\n#define UWS_APP_H\n\n#define _CRT_SECURE_NO_WARNINGS\n\n#include <string>\n#include <charconv>\n#include <string_view>\n\nnamespace uWS {\n    /* Safari 15.0 - 15.3 has a completely broken compression implementation (client_no_context_takeover not\n     * properly implemented) - so we fully disable compression for this browser :-(\n     * see https://github.com/uNetworking/uWebSockets/issues/1347 */\n    inline bool hasBrokenCompression(std::string_view userAgent) {\n        size_t posStart = userAgent.find(\" Version/15.\");\n        if (posStart == std::string_view::npos) return false;\n        posStart += 12;\n\n        size_t posEnd = userAgent.find(' ', posStart);\n        if (posEnd == std::string_view::npos) return false;\n\n        unsigned int minorVersion = 0;\n        auto result = std::from_chars(userAgent.data() + posStart, userAgent.data() + posEnd, minorVersion);\n        if (result.ec != std::errc()) return false;\n        if (result.ptr != userAgent.data() + posEnd) return false; // do not accept trailing chars\n        if (minorVersion > 3) return false; // we target just Safari 15.0 - 15.3\n\n        if (userAgent.find(\" Safari/\", posEnd) == std::string_view::npos) return false;\n\n        return true;\n    }\n}\n\n/* An app is a convenience wrapper of some of the most used fuctionalities and allows a\n * builder-pattern kind of init. Apps operate on the implicit thread local Loop */\n\n#include \"HttpContext.h\"\n#include \"HttpResponse.h\"\n#include \"WebSocketContext.h\"\n#include \"WebSocket.h\"\n#include \"PerMessageDeflate.h\"\n\nnamespace uWS {\n\n    /* This one matches us_socket_context_options_t but has default values */\n    struct SocketContextOptions {\n        const char *key_file_name = nullptr;\n        const char *cert_file_name = nullptr;\n        const char *passphrase = nullptr;\n        const char *dh_params_file_name = nullptr;\n        const char *ca_file_name = nullptr;\n        const char *ssl_ciphers = nullptr;\n        int ssl_prefer_low_memory_usage = 0;\n\n        /* Conversion operator used internally */\n        operator struct us_socket_context_options_t() const {\n            struct us_socket_context_options_t socket_context_options;\n            memcpy(&socket_context_options, this, sizeof(SocketContextOptions));\n            return socket_context_options;\n        }\n    };\n\n    static_assert(sizeof(struct us_socket_context_options_t) == sizeof(SocketContextOptions), \"Mismatching uSockets/uWebSockets ABI\");\n\ntemplate <bool SSL>\nstruct TemplatedApp {\nprivate:\n    /* The app always owns at least one http context, but creates websocket contexts on demand */\n    HttpContext<SSL> *httpContext;\n    /* WebSocketContexts are of differing type, but we as owners and creators must delete them correctly */\n    std::vector<MoveOnlyFunction<void()>> webSocketContextDeleters;\n\n    std::vector<void *> webSocketContexts;\n\npublic:\n\n    TopicTree<TopicTreeMessage, TopicTreeBigMessage> *topicTree = nullptr;\n\n    /* Server name */\n    TemplatedApp &&addServerName(std::string hostname_pattern, SocketContextOptions options = {}) {\n\n        /* Do nothing if not even on SSL */\n        if constexpr (SSL) {\n            /* First we create a new router for this domain */\n            auto *domainRouter = new HttpRouter<typename HttpContextData<SSL>::RouterData>();\n\n            us_socket_context_add_server_name(SSL, (struct us_socket_context_t *) httpContext, hostname_pattern.c_str(), options, domainRouter);\n        }\n\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    TemplatedApp &&removeServerName(std::string hostname_pattern) {\n    \n        /* This will do for now, would be better if us_socket_context_remove_server_name returned the user data */\n        auto *domainRouter = us_socket_context_find_server_name_userdata(SSL, (struct us_socket_context_t *) httpContext, hostname_pattern.c_str());\n        if (domainRouter) {\n            delete (HttpRouter<typename HttpContextData<SSL>::RouterData> *) domainRouter;\n        }\n\n        us_socket_context_remove_server_name(SSL, (struct us_socket_context_t *) httpContext, hostname_pattern.c_str());\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    TemplatedApp &&missingServerName(MoveOnlyFunction<void(const char *hostname)> handler) {\n\n        if (!constructorFailed()) {\n            httpContext->getSocketContextData()->missingServerNameHandler = std::move(handler);\n\n            us_socket_context_on_server_name(SSL, (struct us_socket_context_t *) httpContext, [](struct us_socket_context_t *context, const char *hostname) {\n\n                /* This is the only requirements of being friends with HttpContextData */\n                HttpContext<SSL> *httpContext = (HttpContext<SSL> *) context;\n                httpContext->getSocketContextData()->missingServerNameHandler(hostname);\n            });\n        }\n\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    /* Returns the SSL_CTX of this app, or nullptr. */\n    void *getNativeHandle() {\n        return us_socket_context_get_native_handle(SSL, (struct us_socket_context_t *) httpContext);\n    }\n\n    /* Attaches a \"filter\" function to track socket connections/disconnections */\n    TemplatedApp &&filter(MoveOnlyFunction<void(HttpResponse<SSL> *, int)> &&filterHandler) {\n        httpContext->filter(std::move(filterHandler));\n\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    /* Same as publish, but takes a prepared message */\n    bool publishPrepared(std::string_view topic, PreparedMessage &preparedMessage) {\n        /* It is assumed by heuristics that a prepared message ought to be big,\n         * and so there is no fast path for small messages (yet?) as preparing a small message is unlikely */\n\n        return reinterpret_cast<TopicTree<TopicTreeMessage, PreparedMessage *> *>(topicTree)->publishBig(nullptr, topic, &preparedMessage, [](Subscriber *s, PreparedMessage *preparedMessage) {\n            auto *ws = (WebSocket<SSL, true, int> *) s->user;\n\n            /* Send will drain if needed */\n            ws->sendPrepared(*preparedMessage);\n        });\n    }\n\n    /* Publishes a message to all websocket contexts - conceptually as if publishing to the one single\n     * TopicTree of this app (technically there are many TopicTrees, however the concept is that one\n     * app has one conceptual Topic tree) */\n    bool publish(std::string_view topic, std::string_view message, OpCode opCode, bool compress = false) {\n        /* Anything big bypasses corking efforts */\n        if (message.length() >= LoopData::CORK_BUFFER_SIZE) {\n            return topicTree->publishBig(nullptr, topic, {message, opCode, compress}, [](Subscriber *s, TopicTreeBigMessage &message) {\n                auto *ws = (WebSocket<SSL, true, int> *) s->user;\n\n                /* Send will drain if needed */\n                ws->send(message.message, (OpCode)message.opCode, message.compress);\n            });\n        } else {\n            return topicTree->publish(nullptr, topic, {std::string(message), opCode, compress});\n        }\n    }\n\n    /* Returns number of subscribers for this topic, or 0 for failure.\n     * This function should probably be optimized a lot in future releases,\n     * it could be O(1) with a hash map of fullnames and their counts. */\n    unsigned int numSubscribers(std::string_view topic) {\n        Topic *t = topicTree->lookupTopic(topic);\n        if (t) {\n            return (unsigned int) t->size();\n        }\n\n        return 0;\n    }\n\n    ~TemplatedApp() {\n        /* Let's just put everything here */\n        if (httpContext) {\n            httpContext->free();\n\n            /* Free all our webSocketContexts in a type less way */\n            for (auto &webSocketContextDeleter : webSocketContextDeleters) {\n                webSocketContextDeleter();\n            }\n        }\n\n        /* Delete TopicTree */\n        if (topicTree) {\n            /* And unregister loop callbacks */\n            /* We must unregister any loop post handler here */\n            Loop::get()->removePostHandler(topicTree);\n            Loop::get()->removePreHandler(topicTree);\n\n        delete topicTree;\n        }\n    }\n\n    /* Disallow copying, only move */\n    TemplatedApp(const TemplatedApp &other) = delete;\n\n    TemplatedApp(TemplatedApp &&other) {\n        /* Move HttpContext */\n        httpContext = other.httpContext;\n        other.httpContext = nullptr;\n\n        /* Move webSocketContextDeleters */\n        webSocketContextDeleters = std::move(other.webSocketContextDeleters);\n\n        webSocketContexts = std::move(other.webSocketContexts);\n\n        /* Move TopicTree */\n        topicTree = other.topicTree;\n        other.topicTree = nullptr;\n    }\n\n    TemplatedApp(SocketContextOptions options = {}) {\n        httpContext = HttpContext<SSL>::create(Loop::get(), options);\n\n        /* Register default handler for 404 (can be overridden by user) */\n        this->any(\"/*\", [](auto *res, auto */*req*/) {\n            res->writeStatus(\"404 File Not Found\");\n            res->end(\"<html><body><h1>File Not Found</h1><hr><i>uWebSockets/20 Server</i></body></html>\");\n        });\n    }\n\n    TemplatedApp& operator=(const TemplatedApp&) = delete;\n\n    TemplatedApp& operator=(TemplatedApp&& other) {\n        std::swap(this->httpContext, other.httpContext);\n        std::swap(this->topicTree, other.topicTree);\n        std::swap(this->webSocketContextDeleters, other.webSocketContextDeleters);\n        std::swap(this->webSocketContexts, other.webSocketContexts);\n    }\n\n    bool constructorFailed() {\n        return !httpContext;\n    }\n\n    template <typename UserData>\n    struct WebSocketBehavior {\n        /* Disabled compression by default - probably a bad default */\n        CompressOptions compression = DISABLED;\n        /* Maximum message size we can receive */\n        unsigned int maxPayloadLength = 16 * 1024;\n        /* 2 minutes timeout is good */\n        unsigned short idleTimeout = 120;\n        /* 64kb backpressure is probably good */\n        unsigned int maxBackpressure = 64 * 1024;\n        bool closeOnBackpressureLimit = false;\n        /* This one depends on kernel timeouts and is a bad default */\n        bool resetIdleTimeoutOnSend = false;\n        /* A good default, esp. for newcomers */\n        bool sendPingsAutomatically = true;\n        /* Maximum socket lifetime in minutes before forced closure (defaults to disabled) */\n        unsigned short maxLifetime = 0;\n        MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *, struct us_socket_context_t *)> upgrade = nullptr;\n        MoveOnlyFunction<void(WebSocket<SSL, true, UserData> *)> open = nullptr;\n        MoveOnlyFunction<void(WebSocket<SSL, true, UserData> *, std::string_view, OpCode)> message = nullptr;\n        MoveOnlyFunction<void(WebSocket<SSL, true, UserData> *, std::string_view, OpCode)> dropped = nullptr;\n        MoveOnlyFunction<void(WebSocket<SSL, true, UserData> *)> drain = nullptr;\n        MoveOnlyFunction<void(WebSocket<SSL, true, UserData> *, std::string_view)> ping = nullptr;\n        MoveOnlyFunction<void(WebSocket<SSL, true, UserData> *, std::string_view)> pong = nullptr;\n        MoveOnlyFunction<void(WebSocket<SSL, true, UserData> *, std::string_view, int, int)> subscription = nullptr;\n        MoveOnlyFunction<void(WebSocket<SSL, true, UserData> *, int, std::string_view)> close = nullptr;\n    };\n\n    /* Closes all sockets including listen sockets. */\n    TemplatedApp &&close() {\n        us_socket_context_close(SSL, (struct us_socket_context_t *) httpContext);\n        for (void *webSocketContext : webSocketContexts) {\n            us_socket_context_close(SSL, (struct us_socket_context_t *) webSocketContext);\n        }\n\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    template <typename UserData>\n    TemplatedApp &&ws(std::string pattern, WebSocketBehavior<UserData> &&behavior) {\n        /* Don't compile if alignment rules cannot be satisfied */\n        static_assert(alignof(UserData) <= LIBUS_EXT_ALIGNMENT,\n        \"µWebSockets cannot satisfy UserData alignment requirements. You need to recompile µSockets with LIBUS_EXT_ALIGNMENT adjusted accordingly.\");\n\n        if (!httpContext) {\n            return std::move(static_cast<TemplatedApp &&>(*this));\n        }\n\n        /* Terminate on misleading idleTimeout values */\n        if (behavior.idleTimeout && behavior.idleTimeout < 8) {\n            std::cerr << \"Error: idleTimeout must be either 0 or greater than 8!\" << std::endl;\n            std::terminate();\n        }\n\n        /* Maximum idleTimeout is 16 minutes */\n        if (behavior.idleTimeout > 240 * 4) {\n            std::cerr << \"Error: idleTimeout must not be greater than 960 seconds!\" << std::endl;\n            std::terminate();\n        }\n\n        /* Maximum maxLifetime is 4 hours */\n        if (behavior.maxLifetime > 240) {\n            std::cerr << \"Error: maxLifetime must not be greater than 240 minutes!\" << std::endl;\n            std::terminate();\n        }\n\n        /* If we don't have a TopicTree yet, create one now */\n        if (!topicTree) {\n\n            bool needsUncork = false;\n            topicTree = new TopicTree<TopicTreeMessage, TopicTreeBigMessage>([needsUncork](Subscriber *s, TopicTreeMessage &message, TopicTree<TopicTreeMessage, TopicTreeBigMessage>::IteratorFlags flags) mutable {\n                /* Subscriber's user is the socket */\n                /* Unfortunately we need to cast is to PerSocketData = int\n                 * since many different WebSocketContexts use the same\n                 * TopicTree now */\n                auto *ws = (WebSocket<SSL, true, int> *) s->user;\n\n                /* If this is the first message we try and cork */\n                if (flags & TopicTree<TopicTreeMessage, TopicTreeBigMessage>::IteratorFlags::FIRST) {\n                    if (ws->canCork() && !ws->isCorked()) {\n                        ((AsyncSocket<SSL> *)ws)->cork();\n                        needsUncork = true;\n                    }\n                }\n\n                /* If we ever overstep maxBackpresure, exit immediately */\n                if (WebSocket<SSL, true, int>::SendStatus::DROPPED == ws->send(message.message, (OpCode)message.opCode, message.compress)) {\n                    if (needsUncork) {\n                        ((AsyncSocket<SSL> *)ws)->uncork();\n                        needsUncork = false;\n                    }\n                    /* Stop draining */\n                    return true;\n                }\n\n                /* If this is the last message we uncork if we are corked */\n                if (flags & TopicTree<TopicTreeMessage, TopicTreeBigMessage>::IteratorFlags::LAST) {\n                    /* We should not uncork in all cases? */\n                    if (needsUncork) {\n                        ((AsyncSocket<SSL> *)ws)->uncork();\n                    }\n                }\n\n                /* Success */\n                return false;\n            });\n\n            /* And hook it up with the loop */\n            /* We empty for both pre and post just to make sure */\n            Loop::get()->addPostHandler(topicTree, [topicTree = topicTree](Loop */*loop*/) {\n                /* Commit pub/sub batches every loop iteration */\n                topicTree->drain();\n            });\n\n            Loop::get()->addPreHandler(topicTree, [topicTree = topicTree](Loop */*loop*/) {\n                /* Commit pub/sub batches every loop iteration */\n                topicTree->drain();\n            });\n        }\n\n        /* Every route has its own websocket context with its own behavior and user data type */\n        auto *webSocketContext = WebSocketContext<SSL, true, UserData>::create(Loop::get(), (us_socket_context_t *) httpContext, topicTree);\n\n        /* We need to clear this later on */\n        webSocketContextDeleters.push_back([webSocketContext]() {\n            webSocketContext->free();\n        });\n\n        /* We also keep this list for easy closing */\n        webSocketContexts.push_back((void *)webSocketContext);\n\n        /* Quick fix to disable any compression if set */\n#ifdef UWS_NO_ZLIB\n        behavior.compression = DISABLED;\n#endif\n\n        /* If we are the first one to use compression, initialize it */\n        if (behavior.compression) {\n            LoopData *loopData = (LoopData *) us_loop_ext(us_socket_context_loop(SSL, webSocketContext->getSocketContext()));\n\n            /* Initialize loop's deflate inflate streams */\n            if (!loopData->zlibContext) {\n                loopData->zlibContext = new ZlibContext;\n                loopData->inflationStream = new InflationStream(CompressOptions::DEDICATED_DECOMPRESSOR);\n                loopData->deflationStream = new DeflationStream(CompressOptions::DEDICATED_COMPRESSOR);\n            }\n        }\n\n        /* Copy all handlers */\n        webSocketContext->getExt()->openHandler = std::move(behavior.open);\n        webSocketContext->getExt()->messageHandler = std::move(behavior.message);\n        webSocketContext->getExt()->droppedHandler = std::move(behavior.dropped);\n        webSocketContext->getExt()->drainHandler = std::move(behavior.drain);\n        webSocketContext->getExt()->subscriptionHandler = std::move(behavior.subscription);\n        webSocketContext->getExt()->closeHandler = std::move(behavior.close);\n        webSocketContext->getExt()->pingHandler = std::move(behavior.ping);\n        webSocketContext->getExt()->pongHandler = std::move(behavior.pong);\n\n        /* Copy settings */\n        webSocketContext->getExt()->maxPayloadLength = behavior.maxPayloadLength;\n        webSocketContext->getExt()->maxBackpressure = behavior.maxBackpressure;\n        webSocketContext->getExt()->closeOnBackpressureLimit = behavior.closeOnBackpressureLimit;\n        webSocketContext->getExt()->resetIdleTimeoutOnSend = behavior.resetIdleTimeoutOnSend;\n        webSocketContext->getExt()->sendPingsAutomatically = behavior.sendPingsAutomatically;\n        webSocketContext->getExt()->maxLifetime = behavior.maxLifetime;\n        webSocketContext->getExt()->compression = behavior.compression;\n\n        /* Calculate idleTimeoutCompnents */\n        webSocketContext->getExt()->calculateIdleTimeoutCompnents(behavior.idleTimeout);\n\n        httpContext->onHttp(\"GET\", pattern, [webSocketContext, behavior = std::move(behavior)](auto *res, auto *req) mutable {\n\n            /* If we have this header set, it's a websocket */\n            std::string_view secWebSocketKey = req->getHeader(\"sec-websocket-key\");\n            if (secWebSocketKey.length() == 24) {\n\n                /* Emit upgrade handler */\n                if (behavior.upgrade) {\n\n                    /* Nasty, ugly Safari 15 hack */\n                    if (hasBrokenCompression(req->getHeader(\"user-agent\"))) {\n                        std::string_view secWebSocketExtensions = req->getHeader(\"sec-websocket-extensions\");\n                        memset((void *) secWebSocketExtensions.data(), ' ', secWebSocketExtensions.length());\n                    }\n\n                    behavior.upgrade(res, req, (struct us_socket_context_t *) webSocketContext);\n                } else {\n                    /* Default handler upgrades to WebSocket */\n                    std::string_view secWebSocketProtocol = req->getHeader(\"sec-websocket-protocol\");\n                    std::string_view secWebSocketExtensions = req->getHeader(\"sec-websocket-extensions\");\n\n                    /* Safari 15 hack */\n                    if (hasBrokenCompression(req->getHeader(\"user-agent\"))) {\n                        secWebSocketExtensions = \"\";\n                    }\n\n                    res->template upgrade<UserData>({}, secWebSocketKey, secWebSocketProtocol, secWebSocketExtensions, (struct us_socket_context_t *) webSocketContext);\n                }\n\n                /* We are going to get uncorked by the Http get return */\n\n                /* We do not need to check for any close or shutdown here as we immediately return from get handler */\n\n            } else {\n                /* Tell the router that we did not handle this request */\n                req->setYield(true);\n            }\n        }, true);\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    /* Browse to a server name, changing the router to this domain */\n    TemplatedApp &&domain(std::string serverName) {\n        HttpContextData<SSL> *httpContextData = httpContext->getSocketContextData();\n\n        void *domainRouter = us_socket_context_find_server_name_userdata(SSL, (struct us_socket_context_t *) httpContext, serverName.c_str());\n        if (domainRouter) {\n            std::cout << \"Browsed to SNI: \" << serverName << std::endl;\n            httpContextData->currentRouter = (decltype(httpContextData->currentRouter)) domainRouter;\n        } else {\n            std::cout << \"Cannot browse to SNI: \" << serverName << std::endl;\n            httpContextData->currentRouter = &httpContextData->router;\n        }\n    \n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    TemplatedApp &&get(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {\n        if (httpContext) {\n            httpContext->onHttp(\"GET\", pattern, std::move(handler));\n        }\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    TemplatedApp &&post(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {\n        if (httpContext) {\n            httpContext->onHttp(\"POST\", pattern, std::move(handler));\n        }\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    TemplatedApp &&options(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {\n        if (httpContext) {\n            httpContext->onHttp(\"OPTIONS\", pattern, std::move(handler));\n        }\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    TemplatedApp &&del(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {\n        if (httpContext) {\n            httpContext->onHttp(\"DELETE\", pattern, std::move(handler));\n        }\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    TemplatedApp &&patch(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {\n        if (httpContext) {\n            httpContext->onHttp(\"PATCH\", pattern, std::move(handler));\n        }\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    TemplatedApp &&put(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {\n        if (httpContext) {\n            httpContext->onHttp(\"PUT\", pattern, std::move(handler));\n        }\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    TemplatedApp &&head(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {\n        if (httpContext) {\n            httpContext->onHttp(\"HEAD\", pattern, std::move(handler));\n        }\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    TemplatedApp &&connect(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {\n        if (httpContext) {\n            httpContext->onHttp(\"CONNECT\", pattern, std::move(handler));\n        }\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    TemplatedApp &&trace(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {\n        if (httpContext) {\n            httpContext->onHttp(\"TRACE\", pattern, std::move(handler));\n        }\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    /* This one catches any method */\n    TemplatedApp &&any(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {\n        if (httpContext) {\n            httpContext->onHttp(\"*\", pattern, std::move(handler));\n        }\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    /* Host, port, callback */\n    TemplatedApp &&listen(std::string host, int port, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {\n        if (!host.length()) {\n            return listen(port, std::move(handler));\n        }\n        handler(httpContext ? httpContext->listen(host.c_str(), port, 0) : nullptr);\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    /* Host, port, options, callback */\n    TemplatedApp &&listen(std::string host, int port, int options, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {\n        if (!host.length()) {\n            return listen(port, options, std::move(handler));\n        }\n        handler(httpContext ? httpContext->listen(host.c_str(), port, options) : nullptr);\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    /* Port, callback */\n    TemplatedApp &&listen(int port, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {\n        handler(httpContext ? httpContext->listen(nullptr, port, 0) : nullptr);\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    /* Port, options, callback */\n    TemplatedApp &&listen(int port, int options, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {\n        handler(httpContext ? httpContext->listen(nullptr, port, options) : nullptr);\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    /* options, callback, path to unix domain socket */\n    TemplatedApp &&listen(int options, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler, std::string path) {\n        handler(httpContext ? httpContext->listen(path.c_str(), options) : nullptr);\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    /* callback, path to unix domain socket */\n    TemplatedApp &&listen(MoveOnlyFunction<void(us_listen_socket_t *)> &&handler, std::string path) {\n        handler(httpContext ? httpContext->listen(path.c_str(), 0) : nullptr);\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    /* Register event handler for accepted FD. Can be used together with adoptSocket. */\n    TemplatedApp &&preOpen(LIBUS_SOCKET_DESCRIPTOR (*handler)(struct us_socket_context_t *, LIBUS_SOCKET_DESCRIPTOR)) {\n        httpContext->onPreOpen(handler);\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    TemplatedApp &&removeChildApp(TemplatedApp *app) {\n        /* Remove this app from httpContextData list over child apps and reset round robin */\n        auto &childApps = httpContext->getSocketContextData()->childApps;\n        childApps.erase(\n            std::remove(childApps.begin(), childApps.end(), (void *) app),\n            childApps.end()\n        );\n        httpContext->getSocketContextData()->roundRobin = 0;\n        \n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    TemplatedApp &&addChildApp(TemplatedApp *app) {\n        /* Add this app to httpContextData list over child apps and set onPreOpen */\n        httpContext->getSocketContextData()->childApps.push_back((void *) app);\n        \n        httpContext->onPreOpen([](struct us_socket_context_t *context, LIBUS_SOCKET_DESCRIPTOR fd) -> LIBUS_SOCKET_DESCRIPTOR {\n            \n            HttpContext<SSL> *httpContext = (HttpContext<SSL> *) context;\n\n            if (httpContext->getSocketContextData()->childApps.empty()) {\n                return fd;\n            }\n\n            //std::cout << \"Distributing fd: \" << fd << \" from context: \" << context << std::endl;\n\n            unsigned int *roundRobin = &httpContext->getSocketContextData()->roundRobin;\n\n            //std::cout << \"Round robin is: \" << *roundRobin << \" and size of apps is: \" << httpContext->getSocketContextData()->childApps.size() << std::endl;\n\n            TemplatedApp *receivingApp = (TemplatedApp *) httpContext->getSocketContextData()->childApps[*roundRobin];\n\n\n            //std::cout << \"Loop is \" << receivingApp->getLoop() << std::endl;\n\n\n            receivingApp->getLoop()->defer([fd, receivingApp]() {\n                //std::cout << \"About to adopt socket \" << fd << \" on receivingApp \" << receivingApp << std::endl;\n                receivingApp->adoptSocket(fd);\n                //std::cout << \"Done \" << std::endl;\n            });\n\n            if (++(*roundRobin) == httpContext->getSocketContextData()->childApps.size()) {\n                *roundRobin = 0;\n            }\n\n            return fd + 1;\n        });\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    /* adopt an externally accepted socket */\n    TemplatedApp &&adoptSocket(LIBUS_SOCKET_DESCRIPTOR accepted_fd) {\n        httpContext->adoptAcceptedSocket(accepted_fd);\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    TemplatedApp &&run() {\n        uWS::run();\n        return std::move(static_cast<TemplatedApp &&>(*this));\n    }\n\n    Loop *getLoop() {\n        return (Loop *) httpContext->getLoop();\n    }\n\n};\n\n}\n\nnamespace uWS {\n    typedef uWS::TemplatedApp<false> App;\n    typedef uWS::TemplatedApp<true> SSLApp;\n}\n\n#endif // UWS_APP_H\n"
  },
  {
    "path": "src/AsyncSocket.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2020.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef UWS_ASYNCSOCKET_H\n#define UWS_ASYNCSOCKET_H\n\n/* This class implements async socket memory management strategies */\n\n/* NOTE: Many unsigned/signed conversion warnings could be solved by moving from int length\n * to unsigned length for everything to/from uSockets - this would however remove the opportunity\n * to signal error with -1 (which is how the entire UNIX syscalling is built). */\n\n#include <cstring>\n#include <iostream>\n\n#include \"libusockets.h\"\n\n#include \"LoopData.h\"\n#include \"AsyncSocketData.h\"\n\nnamespace uWS {\n\n    enum SendBufferAttribute {\n        NEEDS_NOTHING,\n        NEEDS_DRAIN,\n        NEEDS_UNCORK\n    };\n\n    template <bool, bool, typename> struct WebSocketContext;\n\ntemplate <bool SSL>\nstruct AsyncSocket {\n    /* This guy is promiscuous */\n    template <bool> friend struct HttpContext;\n    template <bool, bool, typename> friend struct WebSocketContext;\n    template <bool> friend struct TemplatedApp;\n    template <bool, typename> friend struct WebSocketContextData;\n    template <typename, typename> friend struct TopicTree;\n    template <bool> friend struct HttpResponse;\n\nprivate:\n    /* Helper, do not use directly (todo: move to uSockets or de-crazify) */\n    void throttle_helper(int toggle) {\n        /* These should be exposed by uSockets */\n        static thread_local int us_events[2] = {0, 0};\n\n        struct us_poll_t *p = (struct us_poll_t *) this;\n        struct us_loop_t *loop = us_socket_context_loop(SSL, us_socket_context(SSL, (us_socket_t *) this));\n\n        if (toggle) {\n            /* Pause */\n            int events = us_poll_events(p);\n            if (events) {\n                us_events[getBufferedAmount() ? 1 : 0] = events;\n            }\n            us_poll_change(p, loop, 0);\n        } else {\n            /* Resume */\n            int events = us_events[getBufferedAmount() ? 1 : 0];\n            us_poll_change(p, loop, events);\n        }\n    }\n\nprotected:\n    /* Returns SSL pointer or FD as pointer */\n    void *getNativeHandle() {\n        return us_socket_get_native_handle(SSL, (us_socket_t *) this);\n    }\n\n    /* Get loop data for socket */\n    LoopData *getLoopData() {\n        return (LoopData *) us_loop_ext(us_socket_context_loop(SSL, us_socket_context(SSL, (us_socket_t *) this)));\n    }\n\n    /* Get socket extension */\n    AsyncSocketData<SSL> *getAsyncSocketData() {\n        return (AsyncSocketData<SSL> *) us_socket_ext(SSL, (us_socket_t *) this);\n    }\n\n    /* Socket timeout */\n    void timeout(unsigned int seconds) {\n        us_socket_timeout(SSL, (us_socket_t *) this, seconds);\n    }\n\n    /* Shutdown socket without any automatic drainage */\n    void shutdown() {\n        us_socket_shutdown(SSL, (us_socket_t *) this);\n    }\n\n    /* Experimental pause */\n    us_socket_t *pause() {\n        throttle_helper(1);\n        return (us_socket_t *) this;\n    }\n\n    /* Experimental resume */\n    us_socket_t *resume() {\n        throttle_helper(0);\n        return (us_socket_t *) this;\n    }\n\n    /* Immediately close socket */\n    us_socket_t *close() {\n        return us_socket_close(SSL, (us_socket_t *) this, 0, nullptr);\n    }\n\n    void corkUnchecked() {\n        /* What if another socket is corked? */\n        getLoopData()->corkedSocket = this;\n    }\n\n    void uncorkWithoutSending() {\n        if (isCorked()) {\n            getLoopData()->corkedSocket = nullptr;\n        }\n    }\n\n    /* Cork this socket. Only one socket may ever be corked per-loop at any given time */\n    void cork() {\n        /* Extra check for invalid corking of others */\n        if (getLoopData()->corkOffset && getLoopData()->corkedSocket != this) {\n            std::cerr << \"Error: Cork buffer must not be acquired without checking canCork!\" << std::endl;\n            std::terminate();\n        }\n\n        /* What if another socket is corked? */\n        getLoopData()->corkedSocket = this;\n    }\n\n    /* Returns whether we are corked or not */\n    bool isCorked() {\n        return getLoopData()->corkedSocket == this;\n    }\n\n    /* Returns whether we could cork (it is free) */\n    bool canCork() {\n        return getLoopData()->corkedSocket == nullptr;\n    }\n\n    /* Returns a suitable buffer for temporary assemblation of send data */\n    std::pair<char *, SendBufferAttribute> getSendBuffer(size_t size) {\n        /* First step is to determine if we already have backpressure or not */\n        LoopData *loopData = getLoopData();\n        BackPressure &backPressure = getAsyncSocketData()->buffer;\n        size_t existingBackpressure = backPressure.length();\n        if ((!existingBackpressure) && (isCorked() || canCork()) && (loopData->corkOffset + size < LoopData::CORK_BUFFER_SIZE)) {\n            /* Cork automatically if we can */\n            if (isCorked()) {\n                char *sendBuffer = loopData->corkBuffer + loopData->corkOffset;\n                loopData->corkOffset += (unsigned int) size;\n                return {sendBuffer, SendBufferAttribute::NEEDS_NOTHING};\n            } else {\n                cork();\n                char *sendBuffer = loopData->corkBuffer + loopData->corkOffset;\n                loopData->corkOffset += (unsigned int) size;\n                return {sendBuffer, SendBufferAttribute::NEEDS_UNCORK};\n            }\n        } else {\n\n            /* If we are corked and there is already data in the cork buffer,\n            mark how much is ours and reset it */\n            unsigned int ourCorkOffset = 0;\n            if (isCorked() && loopData->corkOffset) {\n                ourCorkOffset = loopData->corkOffset;\n                loopData->corkOffset = 0;\n            }\n\n            /* Fallback is to use the backpressure as buffer */\n            backPressure.resize(ourCorkOffset + existingBackpressure + size);\n\n            /* And copy corkbuffer in front */\n            memcpy((char *) backPressure.data() + existingBackpressure, loopData->corkBuffer, ourCorkOffset);\n\n            return {(char *) backPressure.data() + ourCorkOffset + existingBackpressure, SendBufferAttribute::NEEDS_DRAIN};\n        }\n    }\n\n    /* Returns the user space backpressure. */\n    unsigned int getBufferedAmount() {\n        /* We return the actual amount of bytes in backbuffer, including pendingRemoval */\n        return (unsigned int) getAsyncSocketData()->buffer.totalLength();\n    }\n\n    /* Returns the text representation of an IPv4 or IPv6 address */\n    std::string_view addressAsText(std::string_view binary) {\n        static thread_local char buf[64];\n        int ipLength = 0;\n\n        if (!binary.length()) {\n            return {};\n        }\n\n        unsigned char *b = (unsigned char *) binary.data();\n\n        if (binary.length() == 4) {\n            ipLength = snprintf(buf, 64, \"%u.%u.%u.%u\", b[0], b[1], b[2], b[3]);\n        } else {\n            ipLength = snprintf(buf, 64, \"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\",\n                b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11],\n                b[12], b[13], b[14], b[15]);\n        }\n\n        return {buf, (unsigned int) ipLength};\n    }\n\n    /* Returns the remote IP address or empty string on failure */\n    std::string_view getRemoteAddress() {\n#ifdef UWS_REMOTE_ADDRESS_USERSPACE\n        AsyncSocketData<SSL> *data = getAsyncSocketData();\n        return std::string_view(data->remoteAddress, (unsigned int) data->remoteAddressLength);\n#else\n        static thread_local char buf[16];\n        int ipLength = 16;\n        us_socket_remote_address(SSL, (us_socket_t *) this, buf, &ipLength);\n        return std::string_view(buf, (unsigned int) ipLength);\n#endif\n    }\n\n    /* Returns the text representation of IP */\n    std::string_view getRemoteAddressAsText() {\n        return addressAsText(getRemoteAddress());\n    }\n\n    /* Returns the remote port number or -1 on failure */\n    unsigned int getRemotePort() {\n        int port = us_socket_remote_port(SSL, (us_socket_t *) this);\n        return (unsigned int) port;\n    }\n\n    /* Write in three levels of prioritization: cork-buffer, syscall, socket-buffer. Always drain if possible.\n     * Returns pair of bytes written (anywhere) and whether or not this call resulted in the polling for\n     * writable (or we are in a state that implies polling for writable). */\n    std::pair<int, bool> write(const char *src, int length, bool optionally = false, int nextLength = 0) {\n        /* Fake success if closed, simple fix to allow uncork of closed socket to succeed */\n        if (us_socket_is_closed(SSL, (us_socket_t *) this)) {\n            return {length, false};\n        }\n\n        LoopData *loopData = getLoopData();\n        AsyncSocketData<SSL> *asyncSocketData = getAsyncSocketData();\n\n        /* We are limited if we have a per-socket buffer */\n        if (asyncSocketData->buffer.length()) {\n            /* Write off as much as we can */\n            int written = us_socket_write(SSL, (us_socket_t *) this, asyncSocketData->buffer.data(), (int) asyncSocketData->buffer.length(), /*nextLength != 0 | */length);\n\n            /* On failure return, otherwise continue down the function */\n            if ((unsigned int) written < asyncSocketData->buffer.length()) {\n\n                /* Update buffering (todo: we can do better here if we keep track of what happens to this guy later on) */\n                asyncSocketData->buffer.erase((unsigned int) written);\n\n                if (optionally) {\n                    /* Thankfully we can exit early here */\n                    return {0, true};\n                } else {\n                    /* This path is horrible and points towards erroneous usage */\n                    asyncSocketData->buffer.append(src, (unsigned int) length);\n\n                    return {length, true};\n                }\n            }\n\n            /* At this point we simply have no buffer and can continue as normal */\n            asyncSocketData->buffer.clear();\n        }\n\n        if (length) {\n            if (loopData->corkedSocket == this) {\n                /* We are corked */\n                if (LoopData::CORK_BUFFER_SIZE - loopData->corkOffset >= (unsigned int) length) {\n                    /* If the entire chunk fits in cork buffer */\n                    memcpy(loopData->corkBuffer + loopData->corkOffset, src, (unsigned int) length);\n                    loopData->corkOffset += (unsigned int) length;\n                    /* Fall through to default return */\n                } else {\n                    /* Strategy differences between SSL and non-SSL regarding syscall minimizing */\n                    if constexpr (false) {\n                        /* Cork up as much as we can */\n                        unsigned int stripped = LoopData::CORK_BUFFER_SIZE - loopData->corkOffset;\n                        memcpy(loopData->corkBuffer + loopData->corkOffset, src, stripped);\n                        loopData->corkOffset = LoopData::CORK_BUFFER_SIZE;\n\n                        auto [written, failed] = uncork(src + stripped, length - (int) stripped, optionally);\n                        return {written + (int) stripped, failed};\n                    }\n\n                    /* For non-SSL we take the penalty of two syscalls */\n                    return uncork(src, length, optionally);\n                }\n            } else {\n                /* We are not corked */\n                int written = us_socket_write(SSL, (us_socket_t *) this, src, length, nextLength != 0);\n\n                /* Did we fail? */\n                if (written < length) {\n                    /* If the write was optional then just bail out */\n                    if (optionally) {\n                        return {written, true};\n                    }\n\n                    /* Fall back to worst possible case (should be very rare for HTTP) */\n                    /* At least we can reserve room for next chunk if we know it up front */\n                    if (nextLength) {\n                        asyncSocketData->buffer.reserve(asyncSocketData->buffer.length() + (size_t) (length - written + nextLength));\n                    }\n\n                    /* Buffer this chunk */\n                    asyncSocketData->buffer.append(src + written, (size_t) (length - written));\n\n                    /* Return the failure */\n                    return {length, true};\n                }\n                /* Fall through to default return */\n            }\n        }\n\n        /* Default fall through return */\n        return {length, false};\n    }\n\n    /* Uncork this socket and flush or buffer any corked and/or passed data. It is essential to remember doing this. */\n    /* It does NOT count bytes written from cork buffer (they are already accounted for in the write call responsible for its corking)! */\n    std::pair<int, bool> uncork(const char *src = nullptr, int length = 0, bool optionally = false) {\n        LoopData *loopData = getLoopData();\n\n        if (loopData->corkedSocket == this) {\n            loopData->corkedSocket = nullptr;\n\n            if (loopData->corkOffset) {\n                /* Corked data is already accounted for via its write call */\n                auto [written, failed] = write(loopData->corkBuffer, (int) loopData->corkOffset, false, length);\n                loopData->corkOffset = 0;\n\n                if (failed) {\n                    /* We do not need to care for buffering here, write does that */\n                    return {0, true};\n                }\n            }\n\n            /* We should only return with new writes, not things written to cork already */\n            return write(src, length, optionally, 0);\n        } else {\n            /* We are not even corked! */\n            return {0, false};\n        }\n    }\n};\n\n}\n\n#endif // UWS_ASYNCSOCKET_H\n"
  },
  {
    "path": "src/AsyncSocketData.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2025.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef UWS_ASYNCSOCKETDATA_H\n#define UWS_ASYNCSOCKETDATA_H\n\n#include <string>\n\nnamespace uWS {\n\nstruct BackPressure {\n    std::string buffer;\n    unsigned int pendingRemoval = 0;\n    BackPressure(BackPressure &&other) {\n        buffer = std::move(other.buffer);\n        pendingRemoval = other.pendingRemoval;\n    }\n    BackPressure() = default;\n    void append(const char *data, size_t length) {\n        buffer.append(data, length);\n    }\n    void erase(unsigned int length) {\n        pendingRemoval += length;\n        /* Always erase a minimum of 1/32th the current backpressure */\n        if (pendingRemoval > (buffer.length() >> 5)) {\n            std::string(buffer.begin() + pendingRemoval, buffer.end()).swap(buffer);\n            pendingRemoval = 0;\n        }\n    }\n    size_t length() {\n        return buffer.length() - pendingRemoval;\n    }\n    /* Only used in AsyncSocket::write - what about replacing it with the other functions like erase(length())? */\n    void clear() {\n        pendingRemoval = 0;\n        buffer.clear();\n        buffer.shrink_to_fit();\n    }\n    /* Only used by AsyncSocket::write (optionally) before append */\n    void reserve(size_t length) {\n        buffer.reserve(length + pendingRemoval);\n    }\n    /* Only used by getSendBuffer as last resort */\n    void resize(size_t length) {\n        buffer.resize(length + pendingRemoval);\n    }\n    const char *data() {\n        return buffer.data() + pendingRemoval;\n    }\n    /* The total length, incuding pending removal */\n    size_t totalLength() {\n        return buffer.length();\n    }\n};\n\n/* Depending on how we want AsyncSocket to function, this will need to change */\n\ntemplate <bool SSL>\nstruct AsyncSocketData {\n    /* This will do for now */\n    BackPressure buffer;\n\n#ifdef UWS_REMOTE_ADDRESS_USERSPACE\n    /* Cache for remote address, populated on socket open */\n    char remoteAddress[16];\n    int remoteAddressLength = 0;\n#endif\n\n    /* Allow move constructing us */\n    AsyncSocketData(BackPressure &&backpressure) : buffer(std::move(backpressure)) {\n\n    }\n\n    /* Or emppty */\n    AsyncSocketData() = default;\n};\n\n}\n\n#endif // UWS_ASYNCSOCKETDATA_H\n"
  },
  {
    "path": "src/BloomFilter.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2022.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef UWS_BLOOMFILTER_H\n#define UWS_BLOOMFILTER_H\n\n/* This filter has no false positives or collisions for the standard\n * and non-standard common request headers */\n\n#include <cstdint>\n#include <string_view>\n#include <bitset>\n\nnamespace uWS {\n\nstruct BloomFilter {\nprivate:\n    std::bitset<256> filter;\n    static inline uint32_t perfectHash(uint32_t features) {\n        return features * 1843993368;\n    }\n\n    union ScrambleArea {\n        unsigned char p[4];\n        uint32_t val;\n    };\n\n    ScrambleArea getFeatures(std::string_view key) {\n        ScrambleArea s;\n        s.p[0] = reinterpret_cast<const unsigned char&>(key[0]);\n        s.p[1] = reinterpret_cast<const unsigned char&>(key[key.length() - 1]);\n        s.p[2] = reinterpret_cast<const unsigned char&>(key[key.length() - 2]);\n        s.p[3] = reinterpret_cast<const unsigned char&>(key[key.length() >> 1]);\n        return s;\n    }\n\npublic:\n    bool mightHave(std::string_view key) {\n        if (key.length() < 2) {\n            return true;\n        }\n    \n        ScrambleArea s = getFeatures(key);\n        s.val = perfectHash(s.val);\n        return filter[s.p[0]] &&\n        filter[s.p[1]] &&\n        filter[s.p[2]] &&\n        filter[s.p[3]];\n    }\n\n    void add(std::string_view key) {\n        if (key.length() >= 2) {\n            ScrambleArea s = getFeatures(key);\n            s.val = perfectHash(s.val);\n            filter[s.p[0]] = 1;\n            filter[s.p[1]] = 1;\n            filter[s.p[2]] = 1;\n            filter[s.p[3]] = 1;\n        }\n    }\n\n    void reset() {\n        filter.reset();\n    }\n};\n\n}\n\n#endif // UWS_BLOOMFILTER_H\n"
  },
  {
    "path": "src/CachingApp.h",
    "content": "#ifndef UWS_CACHINGAPP_H\n#define UWS_CACHINGAPP_H\n\n#include \"App.h\"\n#include <unordered_map>\n#include <string>\n#include <functional>\n#include <string_view>\n\nnamespace uWS {\n\nstruct StringViewHash {\n    size_t operator()(std::string_view sv) const {\n        return std::hash<std::string_view>{}(sv);\n    }\n};\n\nstruct StringViewEqual {\n    bool operator()(std::string_view sv1, std::string_view sv2) const {\n        return sv1 == sv2;\n    }\n};\n\n\n\nclass CachingHttpResponse {\npublic:\n    CachingHttpResponse(uWS::HttpResponse<false> *res)\n        : res(res) {}\n\n    void write(std::string_view data) {\n        buffer.append(data);\n    }\n\n    void end(std::string_view data = \"\", bool closeConnection = false) {\n        buffer.append(data);\n\n        // end for all queued up sockets also\n        res->end(buffer);\n\n        created = time(0);\n\n        std::ignore = closeConnection;\n    }\n\npublic:\n    uWS::HttpResponse<false>* res; // should be a vector of waiting sockets\n\n\n    std::string buffer; // body\n    time_t created;\n};\n\ntypedef std::unordered_map<std::string_view, CachingHttpResponse *, \n                       StringViewHash, \n                       StringViewEqual> CacheType;\n\n// we can also derive from H3app later on\ntemplate <bool SSL>\nstruct CachingApp : public uWS::TemplatedAppBase<SSL, CachingApp<SSL>> {\npublic:\n    CachingApp(SocketContextOptions options = {}) : uWS::TemplatedAppBase<SSL, CachingApp<SSL>>(options) {}\n\n    using uWS::TemplatedAppBase<SSL, CachingApp<SSL>>::get;\n\n    CachingApp(const CachingApp &other) = delete;\n    CachingApp(CachingApp<SSL> &&other) : uWS::TemplatedAppBase<SSL, CachingApp<SSL>>(std::move(other)) {\n        // also move the cache\n    }\n\n    ~CachingApp() {\n\n    }\n\n    // variant 1: only taking URL into account\n    CachingApp &&get(const std::string& url, uWS::MoveOnlyFunction<void(CachingHttpResponse*, uWS::HttpRequest*)> &&handler, unsigned int secondsToExpiry) {\n        ((uWS::TemplatedAppBase<SSL, CachingApp<SSL>> *)this)->get(url, [this, handler = std::move(handler), secondsToExpiry](auto* res, auto* req) mutable {\n            /* We need to know the cache key and the time of now */\n            std::string_view cache_key = req->getFullUrl();\n            time_t now = static_cast<LoopData *>(us_loop_ext((us_loop_t *)uWS::Loop::get()))->cacheTimepoint;\n\n            auto it = cache.find(cache_key);\n            if (it != cache.end()) {\n\n                if (it->second->created + secondsToExpiry > now) {\n                    res->end(it->second->buffer); // tryEnd!\n                    return;\n                }\n\n                /* We are no longer valid, delete old cache and fall through to create a new entry */\n                delete it->second;\n\n                // is the cache completed? if not, add yourself to the waiting list of sockets to that cache\n\n                // if the cache completed? ok, is it still valid? use it\n            }\n\n            // immediately take the place in the cache\n            CachingHttpResponse *cachingRes;\n            cache[cache_key] = (cachingRes = new CachingHttpResponse(res));\n\n            handler(cachingRes, req);\n        });\n        return std::move(*this);\n    }\n\n    // variant 2: taking URL and a list of headers into account\n    // todo\n\nprivate:\n    CacheType cache;\n};\n\n}\n#endif"
  },
  {
    "path": "src/ChunkedEncoding.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2026.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef UWS_CHUNKEDENCODING_H\n#define UWS_CHUNKEDENCODING_H\n\n/* Independent chunked encoding parser, used by HttpParser. */\n\n#include <string>\n#include <cstring>\n#include <cstdlib>\n#include <algorithm>\n#include <string_view>\n#include \"MoveOnlyFunction.h\"\n#include <optional>\n\nnamespace uWS {\n\n    constexpr uint64_t STATE_HAS_SIZE = 1ull << (sizeof(uint64_t) * 8 - 1);//0x80000000;\n    constexpr uint64_t STATE_IS_CHUNKED = 1ull << (sizeof(uint64_t) * 8 - 2);//0x40000000;\n    constexpr uint64_t STATE_SIZE_MASK = ~(3ull << (sizeof(uint64_t) * 8 - 2));//0x3FFFFFFF;\n    constexpr uint64_t STATE_IS_ERROR = ~0ull;//0xFFFFFFFF;\n    constexpr uint64_t STATE_SIZE_OVERFLOW = 0x0Full << (sizeof(uint64_t) * 8 - 8);//0x0F000000;\n\n    inline uint64_t chunkSize(uint64_t state) {\n        return state & STATE_SIZE_MASK;\n    }\n\n    /* Reads hex number until CR or out of data to consume. Updates state. Returns bytes consumed. */\n    inline void consumeHexNumber(std::string_view &data, uint64_t &state) {\n        /* Consume everything higher than 32 */\n        while (data.length() && data.data()[0] > 32) {\n\n            unsigned char digit = (unsigned char)data.data()[0];\n            if (digit >= 'a') {\n                digit = (unsigned char) (digit - ('a' - ':'));\n            } else if (digit >= 'A') {\n                digit = (unsigned char) (digit - ('A' - ':'));\n            }\n\n            unsigned int number = ((unsigned int) digit - (unsigned int) '0');\n\n            if (number > 16 || (chunkSize(state) & STATE_SIZE_OVERFLOW)) {\n                state = STATE_IS_ERROR;\n                return;\n            }\n\n            // extract state bits\n            uint64_t bits = /*state &*/ STATE_IS_CHUNKED;\n\n            state = (state & STATE_SIZE_MASK) * 16ull + number;\n\n            state |= bits;\n            data.remove_prefix(1);\n        }\n        /* Consume everything not /n */\n        while (data.length() && data.data()[0] != '\\n') {\n            data.remove_prefix(1);\n        }\n        /* Now we stand on \\n so consume it and enable size */\n        if (data.length()) {\n            state += 2; // include the two last /r/n\n            state |= STATE_HAS_SIZE | STATE_IS_CHUNKED;\n            data.remove_prefix(1);\n        }\n    }\n\n    inline void decChunkSize(uint64_t &state, unsigned int by) {\n\n        //unsigned int bits = state & STATE_IS_CHUNKED;\n\n        state = (state & ~STATE_SIZE_MASK) | (chunkSize(state) - by);\n\n        //state |= bits;\n    }\n\n    inline bool hasChunkSize(uint64_t state) {\n        return state & STATE_HAS_SIZE;\n    }\n\n    /* Are we in the middle of parsing chunked encoding? */\n    inline bool isParsingChunkedEncoding(uint64_t state) {\n        return state & ~STATE_SIZE_MASK;\n    }\n\n    inline bool isParsingInvalidChunkedEncoding(uint64_t state) {\n        return state == STATE_IS_ERROR;\n    }\n\n    /* Returns next chunk (empty or not), or if all data was consumed, nullopt is returned. */\n    static std::optional<std::string_view> getNextChunk(std::string_view &data, uint64_t &state, bool trailer = false) {\n\n        while (data.length()) {\n\n            // if in \"drop trailer mode\", just drop up to what we have as size\n            if (((state & STATE_IS_CHUNKED) == 0) && hasChunkSize(state) && chunkSize(state)) {\n\n                //printf(\"Parsing trailer now\\n\");\n\n                while(data.length() && chunkSize(state)) {\n                    data.remove_prefix(1);\n                    decChunkSize(state, 1);\n\n                    if (chunkSize(state) == 0) {\n\n                        /* This is an actual place where we need 0 as state */\n                        state = 0;\n\n                        /* The parser MUST stop consuming here */\n                        return std::nullopt;\n                    }\n                }\n                continue;\n            }\n\n            if (!hasChunkSize(state)) {\n                consumeHexNumber(data, state);\n                if (isParsingInvalidChunkedEncoding(state)) {\n                    return std::nullopt;\n                }\n                if (hasChunkSize(state) && chunkSize(state) == 2) {\n\n                    //printf(\"Setting state to trailer-parsing and emitting empty chunk\\n\");\n\n                    // set trailer state and increase size to 4\n                    if (trailer) {\n                        state = 4 /*| STATE_IS_CHUNKED*/ | STATE_HAS_SIZE;\n                    } else {\n                        state = 2 /*| STATE_IS_CHUNKED*/ | STATE_HAS_SIZE;\n                    }\n\n                    return std::string_view(nullptr, 0);\n                }\n                continue;\n            }\n\n            // do we have data to emit all?\n            if (data.length() >= chunkSize(state)) {\n                // emit all but 2 bytes then reset state to 0 and goto beginning\n                // not fin\n                std::string_view emitSoon;\n                bool shouldEmit = false;\n                if (chunkSize(state) > 2) {\n                    emitSoon = std::string_view(data.data(), chunkSize(state) - 2);\n                    shouldEmit = true;\n                }\n                data.remove_prefix(chunkSize(state));\n                state = STATE_IS_CHUNKED;\n                if (shouldEmit) {\n                    return emitSoon;\n                }\n                continue;\n            } else {\n                /* We will consume all our input data */\n                std::string_view emitSoon;\n                if (chunkSize(state) > 2) {\n                    uint64_t maximalAppEmit = chunkSize(state) - 2;\n                    if (data.length() > maximalAppEmit) {\n                        emitSoon = data.substr(0, maximalAppEmit);\n                    } else {\n                        //cb(data);\n                        emitSoon = data;\n                    }\n                }\n                decChunkSize(state, (unsigned int) data.length());\n                state |= STATE_IS_CHUNKED;\n                // new: decrease data by its size (bug)\n                data.remove_prefix(data.length()); // ny bug fix för getNextChunk\n                if (emitSoon.length()) {\n                    return emitSoon;\n                } else {\n                    return std::nullopt;\n                }\n            }\n        }\n\n        return std::nullopt;\n    }\n\n    /* This is really just a wrapper for convenience */\n    struct ChunkIterator {\n\n        std::string_view *data;\n        std::optional<std::string_view> chunk;\n        uint64_t *state;\n        bool trailer;\n\n        ChunkIterator(std::string_view *data, uint64_t *state, bool trailer = false) : data(data), state(state), trailer(trailer) {\n            chunk = uWS::getNextChunk(*data, *state, trailer);\n        }\n\n        ChunkIterator() {\n\n        }\n\n        ChunkIterator begin() {\n            return *this;\n        }\n\n        ChunkIterator end() {\n            return ChunkIterator();\n        }\n\n        std::string_view operator*() {\n            if (!chunk.has_value()) {\n                std::abort();\n            }\n            return chunk.value();\n        }\n\n        bool operator!=(const ChunkIterator &other) const {\n            return other.chunk.has_value() != chunk.has_value();\n        }\n\n        ChunkIterator &operator++() {\n            chunk = uWS::getNextChunk(*data, *state, trailer);\n            return *this;\n        }\n\n    };\n}\n\n#endif // UWS_CHUNKEDENCODING_H\n"
  },
  {
    "path": "src/ClientApp.h",
    "content": "#include \"MoveOnlyFunction.h\"\n#include \"WebSocketContext.h\"\n#include <string>\n\nnamespace uWS {\n\n    struct WebSocketClientBehavior {\n        MoveOnlyFunction<void()> open;\n        MoveOnlyFunction<void()> message;\n        MoveOnlyFunction<void()> close;\n        //MoveOnlyFunction<void()> failed;\n\n    };\n\n    struct ClientApp {\n\n        WebSocketContext<0, false, int> *webSocketContext;\n        // behöver ett nytt http context med minimal klient, som slår om till den riktiga websocketcontext\n        // om samma storlek på httpsocket och websocket blir det enkel övergång\n\n        ClientApp(WebSocketClientBehavior &&behavior) {\n            //webSocketContext = WebSocketContext<0, false, int>::create();\n        }\n\n        ClientApp &&connect(std::string url, std::string protocol = \"\") {\n\n            return std::move(*this);\n        }\n\n        void run() {\n\n        }\n\n    };\n\n}"
  },
  {
    "path": "src/Http3App.h",
    "content": "#include \"App.h\"\n\n#include \"Http3Response.h\"\n#include \"Http3Request.h\"\n#include \"Http3Context.h\"\n\nnamespace uWS {\n\n    struct H3App {\n        Http3Context *http3Context;\n\n        H3App(SocketContextOptions options = {}) {\n            /* This conversion should not be needed */\n            us_quic_socket_context_options_t h3options = {};\n\n            h3options.key_file_name = strdup(options.key_file_name);\n            h3options.cert_file_name = strdup(options.cert_file_name);\n            h3options.passphrase = strdup(options.passphrase);\n\n            /* Create the http3 context */\n            http3Context = Http3Context::create((us_loop_t *)Loop::get(), h3options);\n\n            http3Context->init();\n        }\n\n        /* Disallow copying, only move */\n        H3App(const H3App &other) = delete;\n\n        H3App(H3App &&other) {\n            /* Move HttpContext */\n            http3Context = other.http3Context;\n            other.http3Context = nullptr;\n        }\n\n        /* Host, port, callback */\n        H3App &&listen(std::string host, int port, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {\n            if (!host.length()) {\n                return listen(port, std::move(handler));\n            }\n            handler(http3Context ? (us_listen_socket_t *) http3Context->listen(host.c_str(), port) : nullptr);\n            return std::move(*this);\n        }\n\n        /* Host, port, options, callback */\n        H3App &&listen(std::string host, int port, int options, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {\n            if (!host.length()) {\n                return listen(port, options, std::move(handler));\n            }\n            handler(http3Context ? (us_listen_socket_t *) http3Context->listen(host.c_str(), port) : nullptr);\n            return std::move(*this);\n        }\n\n        /* Port, callback */\n        H3App &&listen(int port, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {\n            handler(http3Context ? (us_listen_socket_t *) http3Context->listen(nullptr, port) : nullptr);\n            return std::move(*this);\n        }\n\n        /* Port, options, callback */\n        H3App &&listen(int port, int options, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {\n            handler(http3Context ? (us_listen_socket_t *) http3Context->listen(nullptr, port) : nullptr);\n            return std::move(*this);\n        }\n\n        H3App &&get(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {\n            if (http3Context) {\n                http3Context->onHttp(\"GET\", pattern, std::move(handler));\n            }\n            return std::move(*this);\n        }\n\n        H3App &&post(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {\n            if (http3Context) {\n                http3Context->onHttp(\"POST\", pattern, std::move(handler));\n            }\n            return std::move(*this);\n        }\n\n        H3App &&options(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {\n            if (http3Context) {\n                http3Context->onHttp(\"OPTIONS\", pattern, std::move(handler));\n            }\n            return std::move(*this);\n        }\n\n        H3App &&del(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {\n            if (http3Context) {\n                http3Context->onHttp(\"DELETE\", pattern, std::move(handler));\n            }\n            return std::move(*this);\n        }\n\n        H3App &&patch(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {\n            if (http3Context) {\n                http3Context->onHttp(\"PATCH\", pattern, std::move(handler));\n            }\n            return std::move(*this);\n        }\n\n        H3App &&put(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {\n            if (http3Context) {\n                http3Context->onHttp(\"PUT\", pattern, std::move(handler));\n            }\n            return std::move(*this);\n        }\n\n        H3App &&head(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {\n            if (http3Context) {\n                http3Context->onHttp(\"HEAD\", pattern, std::move(handler));\n            }\n            return std::move(*this);\n        }\n\n        H3App &&connect(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {\n            if (http3Context) {\n                http3Context->onHttp(\"CONNECT\", pattern, std::move(handler));\n            }\n            return std::move(*this);\n        }\n\n        H3App &&trace(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {\n            if (http3Context) {\n                http3Context->onHttp(\"TRACE\", pattern, std::move(handler));\n            }\n            return std::move(*this);\n        }\n\n        /* This one catches any method */\n        H3App &&any(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {\n            if (http3Context) {\n                http3Context->onHttp(\"*\", pattern, std::move(handler));\n            }\n            return std::move(*this);\n        }\n\n        void run() {\n            uWS::Loop::get()->run();\n        }\n    };\n}"
  },
  {
    "path": "src/Http3Context.h",
    "content": "\nextern \"C\" {\n#include \"quic.h\"\n}\n\n#include \"Http3ContextData.h\"\n#include \"Http3ResponseData.h\"\n\nnamespace uWS {\n    struct Http3Context {\n        static Http3Context *create(us_loop_t *loop, us_quic_socket_context_options_t options) {\n\n            /* Create quic socket context (assumes h3 for now) */\n            auto *context = us_create_quic_socket_context(loop, options, sizeof(Http3ContextData));\n\n            /* Specify application callbacks */\n            us_quic_socket_context_on_stream_data(context, [](us_quic_stream_t *s, char *data, int length) {\n\n                Http3ResponseData *responseData = (Http3ResponseData *) us_quic_stream_ext(s);\n                \n                /* We never emit FIN here */\n                if (responseData->onData) {\n                    responseData->onData({data, (size_t) length}, false);\n                }\n            });\n            us_quic_socket_context_on_stream_end(context, [](us_quic_stream_t *s) {\n\n                Http3ResponseData *responseData = (Http3ResponseData *) us_quic_stream_ext(s);\n                \n                /* Emit FIN to app */\n                if (responseData->onData) {\n                    responseData->onData({nullptr, 0}, true);\n                }\n\n                /* Have we written our entire backpressure, if any? */\n                // if (responseData->buffer.length() && (responseData->bufferOffset == (int) responseData->buffer.length())) {\n                //     printf(\"We got FIN and we have no backpressure, closing stream now!\\n\");\n                //     //us_quic_stream_close(s);\n                // } else {\n                //     //printf(\"We got FIN but we have data to write, so keeping connection half-closed!\\n\");\n                // }\n\n            });\n            us_quic_socket_context_on_stream_open(context, [](us_quic_stream_t *s, int is_client) {\n\n                printf(\"Stream open!\\n\");\n\n                /* Inplace init our per stream data */\n                new (us_quic_stream_ext(s)) Http3ResponseData();\n            });\n            us_quic_socket_context_on_close(context, [](us_quic_socket_t *s) {\n                printf(\"QUIC socket disconnected!\\n\");\n            });\n            us_quic_socket_context_on_stream_writable(context, [](us_quic_stream_t *s) {\n                Http3ResponseData *responseData = (Http3ResponseData *) us_quic_stream_ext(s);\n\n                /* Either we handle the streaming or we let the application handle it */\n                if (responseData->onWritable) {\n                    responseData->onWritable(responseData->offset);\n                } else {\n                    int written = us_quic_stream_write(s, (char *) responseData->backpressure.data(), responseData->backpressure.length());\n                    responseData->backpressure.erase(written);\n\n                    if (responseData->backpressure.length() == 0) {\n                        printf(\"wrote until end, shutting down now!\\n\");\n                        us_quic_stream_shutdown(s);\n                        us_quic_stream_close(s);\n                    }\n                }\n            });\n            us_quic_socket_context_on_stream_headers(context, [](us_quic_stream_t *s) {\n\n                /* This is the main place of start for requests */\n                Http3ContextData *contextData = (Http3ContextData *) us_quic_socket_context_ext(us_quic_socket_context(us_quic_stream_socket(s)));\n\n                Http3Request *req = nullptr;\n\n                std::string_view upperCasedMethod = req->getHeader(\":method\");\n                std::string_view path = req->getHeader(\":path\");\n                \n                contextData->router.getUserData() = {(Http3Response *) s, (Http3Request *) nullptr};\n                contextData->router.route(upperCasedMethod, path);\n\n            });\n            us_quic_socket_context_on_open(context, [](us_quic_socket_t *s, int is_client) {\n                printf(\"QUIC socket connected!\\n\");\n            });\n            us_quic_socket_context_on_stream_close(context, [](us_quic_stream_t *s) {\n\n                printf(\"Stream closed!\\n\");\n\n                //lsquic_stream_has_unacked_data\n\n                Http3ResponseData *responseData = (Http3ResponseData *) us_quic_stream_ext(s);\n                \n                if (responseData->onAborted) {\n                    responseData->onAborted();\n                }\n\n                //printf(\"Freeing per stream data in on_stream_close in uws!\\n\");\n\n                responseData->~Http3ResponseData();\n            });\n\n            return (Http3Context *) context;\n\n            // call init here after setting the ext to Http3ContextData\n        }\n\n        us_quic_listen_socket_t *listen(const char *host, int port) {\n            /* The listening socket is the actual UDP socket used */\n            us_quic_listen_socket_t *listen_socket = us_quic_socket_context_listen((us_quic_socket_context_t *) this, host, port, sizeof(Http3ResponseData));\n\n            //printf(\"Listen socket is: %p\\n\", listen_socket);\n\n            return listen_socket;\n        }\n\n        void init() {\n            // set all callbacks here\n\n\n\n            Http3ContextData *contextData = (Http3ContextData *) us_quic_socket_context_ext((us_quic_socket_context_t *) this);\n\n            //printf(\"init: %p\\n\", contextData);\n\n            new (contextData) Http3ContextData();\n\n        }\n\n        // generic for get, post, any, etc\n        void onHttp(std::string method, std::string path, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&cb) {\n            // modifies the router we own as part of Http3ContextData, used in callbacks set in init\n        \n            Http3ContextData *contextData = (Http3ContextData *) us_quic_socket_context_ext((us_quic_socket_context_t *) this);\n\n            /* Todo: This is ugly, fix */\n            std::vector<std::string> methods;\n            if (method == \"*\") {\n                methods = {\"*\"}; //bug! needs to be upper cased!\n                // router.upperCasedMethods;\n            } else {\n                methods = {method};\n            }\n\n            contextData->router.add(methods, path, [handler = std::move(cb)](HttpRouter<Http3ContextData::RouterData> *router) mutable {\n\n                Http3ContextData::RouterData &routerData = router->getUserData();\n\n                handler(routerData.res, routerData.req);\n\n                return true;\n            });\n        }\n    };\n}"
  },
  {
    "path": "src/Http3ContextData.h",
    "content": "#include \"HttpRouter.h\"\n\nstruct Http3Response;\nstruct Http3Request;\n\nnamespace uWS {\n\n    struct Http3ContextData {\n        struct RouterData {\n            Http3Response *res;\n            Http3Request *req;\n        };\n\n        HttpRouter<RouterData> router;\n\n        Http3ContextData() {\n            //printf(\"Constructing http3contextdata: %p\\n\", this);\n        }\n    };\n    \n}"
  },
  {
    "path": "src/Http3Request.h",
    "content": "extern \"C\" {\n#include \"quic.h\"\n}\n\nnamespace uWS {\n\n    struct Http3Request {\n\n        std::string_view getHeader(std::string_view key) {\n            for (int i = 0, more = 1; more; i++) {\n                char *name, *value;\n                int name_length, value_length;\n                if ((more = us_quic_socket_context_get_header(nullptr, i, &name, &name_length, &value, &value_length))) {\n                    if (name_length == (int) key.length() && !memcmp(name, key.data(), key.length())) {\n                        return {value, (size_t) value_length};\n                    }\n                }\n            }\n            return {nullptr, 0};\n        }\n    };\n}"
  },
  {
    "path": "src/Http3Response.h",
    "content": "extern \"C\" {\n#include \"quic.h\"\n}\n\n#include \"Http3ResponseData.h\"\n\nnamespace uWS {\n\n    /* Is a quic stream */\n    struct Http3Response {\n\n        // this one is AsyncSocket, so it has to translate to the stream - abrupt stream termination\n        void close() {\n            //us_quic_stream_close((us_quic_stream_t *) this);\n        }\n\n        void endWithoutBody(std::optional<size_t> reportedContentLength = std::nullopt, bool closeConnection = false) {\n\n        }\n\n        Http3Response *writeStatus(std::string_view status) {\n            Http3ResponseData *responseData = (Http3ResponseData *) us_quic_stream_ext((us_quic_stream_t *) this);\n\n            /* Nothing is done if status already written */\n            if (responseData->headerOffset == 0) {\n                us_quic_socket_context_set_header(nullptr, 0, (char *) \":status\", 7, status.data(), status.length());\n                responseData->headerOffset = 1;\n            }\n\n            return this;\n        }\n\n        Http3Response *writeHeader(std::string_view key, std::string_view value) {\n            Http3ResponseData *responseData = (Http3ResponseData *) us_quic_stream_ext((us_quic_stream_t *) this);\n\n            writeStatus(\"200 OK\");\n\n            us_quic_socket_context_set_header(nullptr, responseData->headerOffset++, key.data(), key.length(), value.data(), value.length());\n\n            return this;\n        }\n\n        std::pair<bool, bool> tryEnd(std::string_view data, uintmax_t totalSize = 0) {\n            Http3ResponseData *responseData = (Http3ResponseData *) us_quic_stream_ext((us_quic_stream_t *) this);\n\n            writeStatus(\"200 OK\");\n\n            us_quic_socket_context_send_headers(nullptr, (us_quic_stream_t *) this, responseData->headerOffset, data.length() > 0);\n\n\n            unsigned int written = us_quic_stream_write((us_quic_stream_t *) this, (char *) data.data(), (int) data.length());\n\n            if (written == data.length()) {\n                return {true, true};\n            } else {\n\n                responseData->offset = written;\n\n                return {true, false};\n            }\n\n\n            return {true, true};\n        }\n\n        /* Idnetical */\n        Http3Response *write(std::string_view data) {\n\n\n            return this;\n        }\n\n        /* Identical */\n        void end(std::string_view data = {}, bool closeConnection = false) {\n\n            Http3ResponseData *responseData = (Http3ResponseData *) us_quic_stream_ext((us_quic_stream_t *) this);\n\n            /* If not already written */\n            writeStatus(\"200 OK\");\n            \n            // has body is determined by the ending so this is perfect here\n            us_quic_socket_context_send_headers(nullptr, (us_quic_stream_t *) this, responseData->headerOffset, data.length() > 0);\n\n            /* Write body and shutdown (unknown if content-length must be present?) */\n            unsigned int written = us_quic_stream_write((us_quic_stream_t *) this, (char *) data.data(), (int) data.length());\n\n            /* Buffer up remains */\n            if (written != data.length()) {\n                responseData->backpressure.append(data.data() + written, data.length() - written);\n            } else {\n                /* Every request has its own stream, so we conceptually serve requests like in HTTP 1.0 */\n                us_quic_stream_shutdown((us_quic_stream_t *) this);\n            }\n        }\n\n        /* Attach handler for aborted HTTP request */\n        Http3Response *onAborted(MoveOnlyFunction<void()> &&handler) {\n            Http3ResponseData *responseData = (Http3ResponseData *) us_quic_stream_ext((us_quic_stream_t *) this);\n\n            responseData->onAborted = std::move(handler);\n            return this;\n        }\n\n        /* Attach a read handler for data sent. Will be called with FIN set true if last segment. */\n        Http3Response *onData(MoveOnlyFunction<void(std::string_view, bool)> &&handler) {\n            Http3ResponseData *responseData = (Http3ResponseData *) us_quic_stream_ext((us_quic_stream_t *) this);\n\n            responseData->onData = std::move(handler);\n            return this;\n        }\n\n        Http3Response *onWritable(MoveOnlyFunction<bool(uintmax_t)> &&handler) {\n            Http3ResponseData *responseData = (Http3ResponseData *) us_quic_stream_ext((us_quic_stream_t *) this);\n\n            responseData->onWritable = std::move(handler);\n            return this;\n        }\n    };\n\n}"
  },
  {
    "path": "src/Http3ResponseData.h",
    "content": "#ifndef UWS_H3RESPONSEDATA_H\n#define UWS_H3RESPONSEDATA_H\n\n#include \"MoveOnlyFunction.h\"\n#include \"AsyncSocketData.h\"\n#include <string_view>\n\nnamespace uWS {\n    struct Http3ResponseData {\n\n        MoveOnlyFunction<void()> onAborted = nullptr;\n        MoveOnlyFunction<void(std::string_view, bool)> onData = nullptr;\n        MoveOnlyFunction<bool(uintmax_t)> onWritable = nullptr;\n\n        /* Status is always first header just like for h1 */\n        unsigned int headerOffset = 0;\n        \n        /* Write offset */\n        uintmax_t offset = 0;\n\n        BackPressure backpressure;\n    };\n}\n\n#endif"
  },
  {
    "path": "src/HttpContext.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2026.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef UWS_HTTPCONTEXT_H\n#define UWS_HTTPCONTEXT_H\n\n/* This class defines the main behavior of HTTP and emits various events */\n\n#include \"Loop.h\"\n#include \"HttpContextData.h\"\n#include \"HttpResponseData.h\"\n#include \"AsyncSocket.h\"\n#include \"WebSocketData.h\"\n\n#include <string_view>\n#include <iostream>\n#include \"MoveOnlyFunction.h\"\n\nnamespace uWS {\ntemplate<bool> struct HttpResponse;\n\ntemplate <bool SSL>\nstruct HttpContext {\n    template<bool> friend struct TemplatedApp;\n    template<bool> friend struct HttpResponse;\nprivate:\n    HttpContext() = delete;\n\n    /* Maximum delay allowed until an HTTP connection is terminated due to outstanding request or rejected data (slow loris protection) */\n    static const int HTTP_IDLE_TIMEOUT_S = 10;\n\n    /* Minimum allowed receive throughput per second (clients uploading less than 16kB/sec get dropped) */\n    static const int HTTP_RECEIVE_THROUGHPUT_BYTES = 16 * 1024;\n\n    us_loop_t *getLoop() {\n        return us_socket_context_loop(SSL, getSocketContext());\n    }\n\n    us_socket_context_t *getSocketContext() {\n        return (us_socket_context_t *) this;\n    }\n\n    static us_socket_context_t *getSocketContext(us_socket_t *s) {\n        return (us_socket_context_t *) us_socket_context(SSL, s);\n    }\n\n    HttpContextData<SSL> *getSocketContextData() {\n        return (HttpContextData<SSL> *) us_socket_context_ext(SSL, getSocketContext());\n    }\n\n    static HttpContextData<SSL> *getSocketContextDataS(us_socket_t *s) {\n        return (HttpContextData<SSL> *) us_socket_context_ext(SSL, getSocketContext(s));\n    }\n\n    /* Init the HttpContext by registering libusockets event handlers */\n    HttpContext<SSL> *init() {\n        /* Handle socket connections */\n        us_socket_context_on_open(SSL, getSocketContext(), [](us_socket_t *s, int /*is_client*/, char *ip, int ip_length) {\n            /* Any connected socket should timeout until it has a request */\n            us_socket_timeout(SSL, s, HTTP_IDLE_TIMEOUT_S);\n\n            /* Init socket ext */\n            new (us_socket_ext(SSL, s)) HttpResponseData<SSL>;\n\n#ifdef UWS_REMOTE_ADDRESS_USERSPACE\n            /* Copy remote address into per-socket cache for later retrieval */\n            AsyncSocketData<SSL> *asyncSocketData = (AsyncSocketData<SSL> *) us_socket_ext(SSL, s);\n            if (ip_length > 0 && ip_length <= 16) {\n                memcpy(asyncSocketData->remoteAddress, ip, (size_t) ip_length);\n                asyncSocketData->remoteAddressLength = ip_length;\n            } else {\n                asyncSocketData->remoteAddressLength = 0;\n            }\n#else\n            (void) ip;\n            (void) ip_length;\n#endif\n\n            /* Call filter */\n            HttpContextData<SSL> *httpContextData = getSocketContextDataS(s);\n            for (auto &f : httpContextData->filterHandlers) {\n                f((HttpResponse<SSL> *) s, 1);\n            }\n\n            return s;\n        });\n\n        /* Handle socket disconnections */\n        us_socket_context_on_close(SSL, getSocketContext(), [](us_socket_t *s, int /*code*/, void */*reason*/) {\n            /* Get socket ext */\n            HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) us_socket_ext(SSL, s);\n\n            /* Call filter */\n            HttpContextData<SSL> *httpContextData = getSocketContextDataS(s);\n            for (auto &f : httpContextData->filterHandlers) {\n                f((HttpResponse<SSL> *) s, -1);\n            }\n\n            /* Signal broken HTTP request only if we have a pending request */\n            if (httpResponseData->onAborted) {\n                httpResponseData->onAborted();\n            }\n\n            /* Destruct socket ext */\n            httpResponseData->~HttpResponseData<SSL>();\n\n            return s;\n        });\n\n        /* Handle HTTP data streams */\n        us_socket_context_on_data(SSL, getSocketContext(), [](us_socket_t *s, char *data, int length) {\n\n            // total overhead is about 210k down to 180k\n            // ~210k req/sec is the original perf with write in data\n            // ~200k req/sec is with cork and formatting\n            // ~190k req/sec is with http parsing\n            // ~180k - 190k req/sec is with varying routing\n\n            HttpContextData<SSL> *httpContextData = getSocketContextDataS(s);\n\n            /* Do not accept any data while in shutdown state */\n            if (us_socket_is_shut_down(SSL, (us_socket_t *) s)) {\n                return s;\n            }\n\n            HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) us_socket_ext(SSL, s);\n\n            /* Cork this socket */\n            ((AsyncSocket<SSL> *) s)->cork();\n\n            /* Mark that we are inside the parser now */\n            httpContextData->isParsingHttp = true;\n\n            // clients need to know the cursor after http parse, not servers!\n            // how far did we read then? we need to know to continue with websocket parsing data? or?\n\n            void *proxyParser = nullptr;\n#ifdef UWS_WITH_PROXY\n            proxyParser = &httpResponseData->proxyParser;\n#endif\n\n            /* The return value is entirely up to us to interpret. The HttpParser only care for whether the returned value is DIFFERENT or not from passed user */\n            auto [err, returnedSocket] = httpResponseData->consumePostPadded(data, (unsigned int) length, s, proxyParser, [httpContextData](void *s, HttpRequest *httpRequest) -> void * {\n                /* For every request we reset the timeout and hang until user makes action */\n                /* Warning: if we are in shutdown state, resetting the timer is a security issue! */\n                us_socket_timeout(SSL, (us_socket_t *) s, 0);\n\n                /* Reset httpResponse */\n                HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) us_socket_ext(SSL, (us_socket_t *) s);\n                httpResponseData->offset = 0;\n\n                /* Are we not ready for another request yet? Terminate the connection.\n                 * Important for denying async pipelining until, if ever, we want to suppot it.\n                 * Otherwise requests can get mixed up on the same connection. We still support sync pipelining. */\n                if (httpResponseData->state & HttpResponseData<SSL>::HTTP_RESPONSE_PENDING) {\n                    us_socket_close(SSL, (us_socket_t *) s, 0, nullptr);\n                    return nullptr;\n                }\n\n                /* Mark pending request and emit it */\n                httpResponseData->state = HttpResponseData<SSL>::HTTP_RESPONSE_PENDING;\n\n                /* Mark this response as connectionClose if ancient or connection: close */\n                if (httpRequest->isAncient() || httpRequest->getHeader(\"connection\").length() == 5) {\n                    httpResponseData->state |= HttpResponseData<SSL>::HTTP_CONNECTION_CLOSE;\n                }\n\n                /* Select the router based on SNI (only possible for SSL) */\n                auto *selectedRouter = &httpContextData->router;\n                if constexpr (SSL) {\n                    void *domainRouter = us_socket_server_name_userdata(SSL, (struct us_socket_t *) s);\n                    if (domainRouter) {\n                        selectedRouter = (decltype(selectedRouter)) domainRouter;\n                    }\n                }\n\n                /* Route the method and URL */\n                selectedRouter->getUserData() = {(HttpResponse<SSL> *) s, httpRequest};\n                if (!selectedRouter->route(httpRequest->getCaseSensitiveMethod(), httpRequest->getUrl())) {\n                    /* We have to force close this socket as we have no handler for it */\n                    us_socket_close(SSL, (us_socket_t *) s, 0, nullptr);\n                    return nullptr;\n                }\n\n                /* First of all we need to check if this socket was deleted due to upgrade */\n                if (httpContextData->upgradedWebSocket) {\n                    /* We differ between closed and upgraded below */\n                    return nullptr;\n                }\n\n                /* Was the socket closed? */\n                if (us_socket_is_closed(SSL, (struct us_socket_t *) s)) {\n                    return nullptr;\n                }\n\n                /* We absolutely have to terminate parsing if shutdown */\n                if (us_socket_is_shut_down(SSL, (us_socket_t *) s)) {\n                    return nullptr;\n                }\n\n                /* Returning from a request handler without responding or attaching an onAborted handler is ill-use */\n                if (!((HttpResponse<SSL> *) s)->hasResponded() && !httpResponseData->onAborted) {\n                    /* Throw exception here? */\n                    std::cerr << \"Error: Returning from a request handler without responding or attaching an abort handler is forbidden!\"\n                              << std::endl\n                              << \"\\tMethod: \\\"\" << httpRequest->getCaseSensitiveMethod() << \"\\\"\" << std::endl\n                              << \"\\tURL: \\\"\" << httpRequest->getUrl() << \"\\\"\" << std::endl;\n                    std::terminate();\n                }\n\n                /* If we have not responded and we have a data handler, we need to timeout to enfore client sending the data */\n                if (!((HttpResponse<SSL> *) s)->hasResponded() && httpResponseData->inStream) {\n                    us_socket_timeout(SSL, (us_socket_t *) s, HTTP_IDLE_TIMEOUT_S);\n                }\n\n                /* Continue parsing */\n                return s;\n\n            }, [httpResponseData](void *user, std::string_view data, bool fin) -> void * {\n                /* We always get an empty chunk even if there is no data */\n                if (httpResponseData->inStream) {\n\n                    /* Todo: can this handle timeout for non-post as well? */\n                    if (fin) {\n                        /* If we just got the last chunk (or empty chunk), disable timeout */\n                        us_socket_timeout(SSL, (struct us_socket_t *) user, 0);\n                    } else {\n                        /* We still have some more data coming in later, so reset timeout */\n                        /* Only reset timeout if we got enough bytes (16kb/sec) since last time we reset here */\n                        httpResponseData->received_bytes_per_timeout += (unsigned int) data.length();\n                        if (httpResponseData->received_bytes_per_timeout >= HTTP_RECEIVE_THROUGHPUT_BYTES * HTTP_IDLE_TIMEOUT_S) {\n                            us_socket_timeout(SSL, (struct us_socket_t *) user, HTTP_IDLE_TIMEOUT_S);\n                            httpResponseData->received_bytes_per_timeout = 0;\n                        }\n                    }\n\n                    /* We might respond in the handler, so do not change timeout after this */\n                    httpResponseData->inStream(data, fin);\n\n                    /* Was the socket closed? */\n                    if (us_socket_is_closed(SSL, (struct us_socket_t *) user)) {\n                        return nullptr;\n                    }\n\n                    /* We absolutely have to terminate parsing if shutdown */\n                    if (us_socket_is_shut_down(SSL, (us_socket_t *) user)) {\n                        return nullptr;\n                    }\n\n                    /* If we were given the last data chunk, reset data handler to ensure following\n                     * requests on the same socket won't trigger any previously registered behavior */\n                    if (fin) {\n                        httpResponseData->inStream = nullptr;\n                    }\n                }\n                return user;\n            });\n\n            /* Mark that we are no longer parsing Http */\n            httpContextData->isParsingHttp = false;\n\n            /* If we got fullptr that means the parser wants us to close the socket from error (same as calling the errorHandler) */\n            if (returnedSocket == FULLPTR) {\n                /* For errors, we only deliver them \"at most once\". We don't care if they get halfways delivered or not. */\n                us_socket_write(SSL, s, httpErrorResponses[err].data(), (int) httpErrorResponses[err].length(), false);\n                us_socket_shutdown(SSL, s);\n                /* Close any socket on HTTP errors */\n                us_socket_close(SSL, s, 0, nullptr);\n                /* This just makes the following code act as if the socket was closed from error inside the parser. */\n                returnedSocket = nullptr;\n            }\n\n            /* We need to uncork in all cases, except for nullptr (closed socket, or upgraded socket) */\n            if (returnedSocket != nullptr) {\n                /* Timeout on uncork failure */\n                auto [written, failed] = ((AsyncSocket<SSL> *) returnedSocket)->uncork();\n                if (failed) {\n                    /* All Http sockets timeout by this, and this behavior match the one in HttpResponse::cork */\n                    /* Warning: both HTTP_IDLE_TIMEOUT_S and HTTP_TIMEOUT_S are 10 seconds and both are used the same */\n                    ((AsyncSocket<SSL> *) s)->timeout(HTTP_IDLE_TIMEOUT_S);\n                }\n\n                /* We need to check if we should close this socket here now */\n                if (httpResponseData->state & HttpResponseData<SSL>::HTTP_CONNECTION_CLOSE) {\n                    if ((httpResponseData->state & HttpResponseData<SSL>::HTTP_RESPONSE_PENDING) == 0) {\n                        if (((AsyncSocket<SSL> *) s)->getBufferedAmount() == 0) {\n                            ((AsyncSocket<SSL> *) s)->shutdown();\n                            /* We need to force close after sending FIN since we want to hinder\n                             * clients from keeping to send their huge data */\n                            ((AsyncSocket<SSL> *) s)->close();\n                        }\n                    }\n                }\n\n                return (us_socket_t *) returnedSocket;\n            }\n\n            /* If we upgraded, check here (differ between nullptr close and nullptr upgrade) */\n            if (httpContextData->upgradedWebSocket) {\n                /* This path is only for upgraded websockets */\n                AsyncSocket<SSL> *asyncSocket = (AsyncSocket<SSL> *) httpContextData->upgradedWebSocket;\n\n                /* Uncork here as well (note: what if we failed to uncork and we then pub/sub before we even upgraded?) */\n                auto [written, failed] = asyncSocket->uncork();\n\n                /* If we succeeded in uncorking, check if we have sent WebSocket FIN */\n                if (!failed) {\n                    WebSocketData *webSocketData = (WebSocketData *) asyncSocket->getAsyncSocketData();\n                    if (webSocketData->isShuttingDown) {\n                        /* In that case, also send TCP FIN (this is similar to what we have in ws drain handler) */\n                        asyncSocket->shutdown();\n                    }\n                }\n\n                /* Reset upgradedWebSocket before we return */\n                httpContextData->upgradedWebSocket = nullptr;\n\n                /* Return the new upgraded websocket */\n                return (us_socket_t *) asyncSocket;\n            }\n\n            /* It is okay to uncork a closed socket and we need to */\n            ((AsyncSocket<SSL> *) s)->uncork();\n\n            /* We cannot return nullptr to the underlying stack in any case */\n            return s;\n        });\n\n        /* Handle HTTP write out (note: SSL_read may trigger this spuriously, the app need to handle spurious calls) */\n        us_socket_context_on_writable(SSL, getSocketContext(), [](us_socket_t *s) {\n\n            AsyncSocket<SSL> *asyncSocket = (AsyncSocket<SSL> *) s;\n            HttpResponseData<SSL> *httpResponseData = (HttpResponseData<SSL> *) asyncSocket->getAsyncSocketData();\n\n            /* Ask the developer to write data and return success (true) or failure (false), OR skip sending anything and return success (true). */\n            if (httpResponseData->onWritable) {\n                /* We are now writable, so hang timeout again, the user does not have to do anything so we should hang until end or tryEnd rearms timeout */\n                us_socket_timeout(SSL, s, 0);\n\n                /* We expect the developer to return whether or not write was successful (true).\n                 * If write was never called, the developer should still return true so that we may drain. */\n                bool success = httpResponseData->callOnWritable(httpResponseData->offset);\n\n                /* The developer indicated that their onWritable failed. */\n                if (!success) {\n                    /* Skip testing if we can drain anything since that might perform an extra syscall */\n                    return s;\n                }\n\n                /* We don't want to fall through since we don't want to mess with timeout.\n                 * It makes little sense to drain any backpressure when the user has registered onWritable. */\n                return s;\n            }\n\n            /* Drain any socket buffer, this might empty our backpressure and thus finish the request */\n            /*auto [written, failed] = */asyncSocket->write(nullptr, 0, true, 0);\n\n            /* Should we close this connection after a response - and is this response really done? */\n            if (httpResponseData->state & HttpResponseData<SSL>::HTTP_CONNECTION_CLOSE) {\n                if ((httpResponseData->state & HttpResponseData<SSL>::HTTP_RESPONSE_PENDING) == 0) {\n                    if (asyncSocket->getBufferedAmount() == 0) {\n                        asyncSocket->shutdown();\n                        /* We need to force close after sending FIN since we want to hinder\n                         * clients from keeping to send their huge data */\n                        asyncSocket->close();\n                    }\n                }\n            }\n\n            /* Expect another writable event, or another request within the timeout */\n            asyncSocket->timeout(HTTP_IDLE_TIMEOUT_S);\n\n            return s;\n        });\n\n        /* Handle FIN, HTTP does not support half-closed sockets, so simply close */\n        us_socket_context_on_end(SSL, getSocketContext(), [](us_socket_t *s) {\n\n            /* We do not care for half closed sockets */\n            AsyncSocket<SSL> *asyncSocket = (AsyncSocket<SSL> *) s;\n            return asyncSocket->close();\n\n        });\n\n        /* Handle socket timeouts, simply close them so to not confuse client with FIN */\n        us_socket_context_on_timeout(SSL, getSocketContext(), [](us_socket_t *s) {\n\n            /* Force close rather than gracefully shutdown and risk confusing the client with a complete download */\n            AsyncSocket<SSL> *asyncSocket = (AsyncSocket<SSL> *) s;\n            return asyncSocket->close();\n\n        });\n\n        return this;\n    }\n\npublic:\n    /* Construct a new HttpContext using specified loop */\n    static HttpContext *create(Loop *loop, us_socket_context_options_t options = {}) {\n        HttpContext *httpContext;\n\n        httpContext = (HttpContext *) us_create_socket_context(SSL, (us_loop_t *) loop, sizeof(HttpContextData<SSL>), options);\n\n        if (!httpContext) {\n            return nullptr;\n        }\n\n        /* Init socket context data */\n        new ((HttpContextData<SSL> *) us_socket_context_ext(SSL, (us_socket_context_t *) httpContext)) HttpContextData<SSL>();\n        return httpContext->init();\n    }\n\n    /* Destruct the HttpContext, it does not follow RAII */\n    void free() {\n        /* Destruct socket context data */\n        HttpContextData<SSL> *httpContextData = getSocketContextData();\n        httpContextData->~HttpContextData<SSL>();\n\n        /* Free the socket context in whole */\n        us_socket_context_free(SSL, getSocketContext());\n    }\n\n    void filter(MoveOnlyFunction<void(HttpResponse<SSL> *, int)> &&filterHandler) {\n        getSocketContextData()->filterHandlers.emplace_back(std::move(filterHandler));\n    }\n\n    /* Register an HTTP route handler acording to URL pattern */\n    void onHttp(std::string method, std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler, bool upgrade = false) {\n        HttpContextData<SSL> *httpContextData = getSocketContextData();\n\n        /* Todo: This is ugly, fix */\n        std::vector<std::string> methods;\n        if (method == \"*\") {\n            methods = {\"*\"};\n        } else {\n            methods = {method};\n        }\n\n        uint32_t priority = method == \"*\" ? httpContextData->currentRouter->LOW_PRIORITY : (upgrade ? httpContextData->currentRouter->HIGH_PRIORITY : httpContextData->currentRouter->MEDIUM_PRIORITY);\n\n        /* If we are passed nullptr then remove this */\n        if (!handler) {\n            httpContextData->currentRouter->remove(methods[0], pattern, priority);\n            return;\n        }\n\n        /* Record this route's parameter offsets */\n        std::map<std::string, unsigned short, std::less<>> parameterOffsets;\n        unsigned short offset = 0;\n        for (unsigned int i = 0; i < pattern.length(); i++) {\n            if (pattern[i] == ':') {\n                i++;\n                unsigned int start = i;\n                while (i < pattern.length() && pattern[i] != '/') {\n                    i++;\n                }\n                parameterOffsets[std::string(pattern.data() + start, i - start)] = offset;\n                //std::cout << \"<\" << std::string(pattern.data() + start, i - start) << \"> is offset \" << offset;\n                offset++;\n            }\n        }\n\n        httpContextData->currentRouter->add(methods, pattern, [handler = std::move(handler), parameterOffsets = std::move(parameterOffsets)](auto *r) mutable {\n            auto user = r->getUserData();\n            user.httpRequest->setYield(false);\n            user.httpRequest->setParameters(r->getParameters());\n            user.httpRequest->setParameterOffsets(&parameterOffsets);\n\n            /* Middleware? Automatically respond to expectations */\n            std::string_view expect = user.httpRequest->getHeader(\"expect\");\n            if (expect.length() && expect == \"100-continue\") {\n                user.httpResponse->writeContinue();\n            }\n\n            handler(user.httpResponse, user.httpRequest);\n\n            /* If any handler yielded, the router will keep looking for a suitable handler. */\n            if (user.httpRequest->getYield()) {\n                return false;\n            }\n            return true;\n        }, priority);\n    }\n\n    /* Listen to port using this HttpContext */\n    us_listen_socket_t *listen(const char *host, int port, int options) {\n        return us_socket_context_listen(SSL, getSocketContext(), host, port, options, sizeof(HttpResponseData<SSL>));\n    }\n\n    /* Listen to unix domain socket using this HttpContext */\n    us_listen_socket_t *listen(const char *path, int options) {\n        return us_socket_context_listen_unix(SSL, getSocketContext(), path, options, sizeof(HttpResponseData<SSL>));\n    }\n\n    void onPreOpen(LIBUS_SOCKET_DESCRIPTOR (*handler)(struct us_socket_context_t *, LIBUS_SOCKET_DESCRIPTOR)) {\n        us_socket_context_on_pre_open(SSL, getSocketContext(), handler);\n    }\n\n    /* Adopt an externally accepted socket into this HttpContext */\n    us_socket_t *adoptAcceptedSocket(LIBUS_SOCKET_DESCRIPTOR accepted_fd) {\n        return us_adopt_accepted_socket(SSL, getSocketContext(), accepted_fd, sizeof(HttpResponseData<SSL>), 0, 0);\n    }\n};\n\n}\n\n#endif // UWS_HTTPCONTEXT_H\n"
  },
  {
    "path": "src/HttpContextData.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2020.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef UWS_HTTPCONTEXTDATA_H\n#define UWS_HTTPCONTEXTDATA_H\n\n#include \"HttpRouter.h\"\n\n#include <vector>\n#include \"MoveOnlyFunction.h\"\n\nnamespace uWS {\ntemplate<bool> struct HttpResponse;\nstruct HttpRequest;\n\ntemplate <bool SSL>\nstruct alignas(16) HttpContextData {\n    template <bool> friend struct HttpContext;\n    template <bool> friend struct HttpResponse;\n    template <bool> friend struct TemplatedApp;\nprivate:\n    std::vector<MoveOnlyFunction<void(HttpResponse<SSL> *, int)>> filterHandlers;\n\n    MoveOnlyFunction<void(const char *hostname)> missingServerNameHandler;\n\n    struct RouterData {\n        HttpResponse<SSL> *httpResponse;\n        HttpRequest *httpRequest;\n    };\n\n    /* This is the currently browsed-to router when using SNI */\n    HttpRouter<RouterData> *currentRouter = &router;\n\n    /* This is the default router for default SNI or non-SSL */\n    HttpRouter<RouterData> router;\n    void *upgradedWebSocket = nullptr;\n    bool isParsingHttp = false;\n\n    /* If we are main acceptor, distribute to these apps */\n    std::vector<void *> childApps;\n    unsigned int roundRobin = 0;\n};\n\n}\n\n#endif // UWS_HTTPCONTEXTDATA_H\n"
  },
  {
    "path": "src/HttpErrors.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2023.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef UWS_HTTP_ERRORS\n#define UWS_HTTP_ERRORS\n\n#include <string_view>\n\nnamespace uWS {\n/* Possible errors from http parsing */\nenum HttpError {\n    HTTP_ERROR_505_HTTP_VERSION_NOT_SUPPORTED = 1,\n    HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE = 2,\n    HTTP_ERROR_400_BAD_REQUEST = 3\n};\n\n#ifndef UWS_HTTPRESPONSE_NO_WRITEMARK\n\n/* Returned parser errors match this LUT. */\nstatic const std::string_view httpErrorResponses[] = {\n    \"\", /* Zeroth place is no error so don't use it */\n    \"HTTP/1.1 505 HTTP Version Not Supported\\r\\nConnection: close\\r\\n\\r\\n<h1>HTTP Version Not Supported</h1><p>This server does not support HTTP/1.0.</p><hr><i>uWebSockets/20 Server</i>\",\n    \"HTTP/1.1 431 Request Header Fields Too Large\\r\\nConnection: close\\r\\n\\r\\n<h1>Request Header Fields Too Large</h1><hr><i>uWebSockets/20 Server</i>\",\n    \"HTTP/1.1 400 Bad Request\\r\\nConnection: close\\r\\n\\r\\n<h1>Bad Request</h1><hr><i>uWebSockets/20 Server</i>\",\n};\n\n#else\n/* Anonymized pages */\nstatic const std::string_view httpErrorResponses[] = {\n    \"\", /* Zeroth place is no error so don't use it */\n    \"HTTP/1.1 505 HTTP Version Not Supported\\r\\nConnection: close\\r\\n\\r\\n\",\n    \"HTTP/1.1 431 Request Header Fields Too Large\\r\\nConnection: close\\r\\n\\r\\n\",\n    \"HTTP/1.1 400 Bad Request\\r\\nConnection: close\\r\\n\\r\\n\"\n};\n#endif\n\n}\n\n#endif"
  },
  {
    "path": "src/HttpParser.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2024.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef UWS_HTTPPARSER_H\n#define UWS_HTTPPARSER_H\n\n// todo: HttpParser is in need of a few clean-ups and refactorings\n\n/* The HTTP parser is an independent module subject to unit testing / fuzz testing */\n\n#include <string>\n#include <cstring>\n#include <algorithm>\n#include <climits>\n#include <string_view>\n#include <map>\n#include \"MoveOnlyFunction.h\"\n#include \"ChunkedEncoding.h\"\n\n#include \"BloomFilter.h\"\n#include \"ProxyParser.h\"\n#include \"QueryParser.h\"\n#include \"HttpErrors.h\"\n\nnamespace uWS {\n\n/* We require at least this much post padding */\nstatic const unsigned int MINIMUM_HTTP_POST_PADDING = 32;\nstatic void *FULLPTR = (void *)~(uintptr_t)0;\n\n/* STL needs one of these */\ntemplate <typename T>\nstd::optional<T *> optional_ptr(T *ptr) {\n    return ptr ? std::optional<T *>(ptr) : std::nullopt;\n}\n\nstatic const size_t MAX_FALLBACK_SIZE = (size_t) atoi(optional_ptr(getenv(\"UWS_HTTP_MAX_HEADERS_SIZE\")).value_or((char *) \"4096\"));\n#ifndef UWS_HTTP_MAX_HEADERS_COUNT\n#define UWS_HTTP_MAX_HEADERS_COUNT 100\n#endif\n\nstruct HttpRequest {\n\n    friend struct HttpParser;\n\nprivate:\n    struct Header {\n        std::string_view key, value;\n    } headers[UWS_HTTP_MAX_HEADERS_COUNT];\n    bool ancientHttp;\n    unsigned int querySeparator;\n    bool didYield;\n    BloomFilter bf;\n    std::pair<int, std::string_view *> currentParameters;\n    std::map<std::string, unsigned short, std::less<>> *currentParameterOffsets = nullptr;\n\npublic:\n    bool isAncient() {\n        return ancientHttp;\n    }\n\n    bool getYield() {\n        return didYield;\n    }\n\n    /* Iteration over headers (key, value) */\n    struct HeaderIterator {\n        Header *ptr;\n\n        bool operator!=(const HeaderIterator &other) const {\n            /* Comparison with end is a special case */\n            if (ptr != other.ptr) {\n                return other.ptr || ptr->key.length();\n            }\n            return false;\n        }\n\n        HeaderIterator &operator++() {\n            ptr++;\n            return *this;\n        }\n\n        std::pair<std::string_view, std::string_view> operator*() const {\n            return {ptr->key, ptr->value};\n        }\n    };\n\n    HeaderIterator begin() {\n        return {headers + 1};\n    }\n\n    HeaderIterator end() {\n        return {nullptr};\n    }\n\n    /* If you do not want to handle this route */\n    void setYield(bool yield) {\n        didYield = yield;\n    }\n\n    std::string_view getHeader(std::string_view lowerCasedHeader) {\n        if (bf.mightHave(lowerCasedHeader)) {\n            for (Header *h = headers; (++h)->key.length(); ) {\n                if (h->key.length() == lowerCasedHeader.length() && !strncmp(h->key.data(), lowerCasedHeader.data(), lowerCasedHeader.length())) {\n                    return h->value;\n                }\n            }\n        }\n        return std::string_view(nullptr, 0);\n    }\n\n    std::string_view getUrl() {\n        return std::string_view(headers->value.data(), querySeparator);\n    }\n\n    std::string_view getFullUrl() {\n        return std::string_view(headers->value.data(), headers->value.length());\n    }\n\n    /* Hack: this should be getMethod */\n    std::string_view getCaseSensitiveMethod() {\n        return std::string_view(headers->key.data(), headers->key.length());\n    }\n\n    std::string_view getMethod() {\n        /* Compatibility hack: lower case method (todo: remove when major version bumps) */\n        for (unsigned int i = 0; i < headers->key.length(); i++) {\n            ((char *) headers->key.data())[i] |= 32;\n        }\n\n        return std::string_view(headers->key.data(), headers->key.length());\n    }\n\n    /* Returns the raw querystring as a whole, still encoded */\n    std::string_view getQuery() {\n        if (querySeparator < headers->value.length()) {\n            /* Strip the initial ? */\n            return std::string_view(headers->value.data() + querySeparator + 1, headers->value.length() - querySeparator - 1);\n        } else {\n            return std::string_view(nullptr, 0);\n        }\n    }\n\n    /* Finds and decodes the URI component. */\n    std::string_view getQuery(std::string_view key) {\n        /* Raw querystring including initial '?' sign */\n        std::string_view queryString = std::string_view(headers->value.data() + querySeparator, headers->value.length() - querySeparator);\n\n        return getDecodedQueryValue(key, queryString);\n    }\n\n    void setParameters(std::pair<int, std::string_view *> parameters) {\n        currentParameters = parameters;\n    }\n\n    void setParameterOffsets(std::map<std::string, unsigned short, std::less<>> *offsets) {\n        currentParameterOffsets = offsets;\n    }\n\n    std::string_view getParameter(std::string_view name) {\n        if (!currentParameterOffsets) {\n            return {nullptr, 0};\n        }\n        auto it = currentParameterOffsets->find(name);\n        if (it == currentParameterOffsets->end()) {\n            return {nullptr, 0};\n        }\n        return getParameter(it->second);\n    }\n\n    std::string_view getParameter(unsigned short index) {\n        if (currentParameters.first < (int) index) {\n            return {};\n        } else {\n            return currentParameters.second[index];\n        }\n    }\n\n};\n\nstruct HttpParser {\n\nprivate:\n    std::string fallback;\n    /* This guy really has only 30 bits since we reserve two highest bits to chunked encoding parsing state */\n    uint64_t remainingStreamingBytes = 0;\n\n    /* Returns UINT64_MAX on error. Maximum 999999999 is allowed. */\n    static uint64_t toUnsignedInteger(std::string_view str) {\n        /* We assume at least 64-bit integer giving us safely 999999999999999999 (18 number of 9s) */\n        if (str.length() > 18) {\n            return UINT64_MAX;\n        }\n\n        uint64_t unsignedIntegerValue = 0;\n        for (char c : str) {\n            /* As long as the letter is 0-9 we cannot overflow. */\n            if (c < '0' || c > '9') {\n                return UINT64_MAX;\n            }\n            unsignedIntegerValue = unsignedIntegerValue * 10ull + ((unsigned int) c - (unsigned int) '0');\n        }\n        return unsignedIntegerValue;\n    }\n    \n    static inline uint64_t hasLess(uint64_t x, uint64_t n) {\n        return (((x)-~0ULL/255*(n))&~(x)&~0ULL/255*128);\n    }\n\n    static inline uint64_t hasMore(uint64_t x, uint64_t n) {\n        return (( ((x)+~0ULL/255*(127-(n))) |(x))&~0ULL/255*128);\n    }\n\n    static inline uint64_t hasBetween(uint64_t x, uint64_t m, uint64_t n) {\n        return (( (~0ULL/255*(127+(n))-((x)&~0ULL/255*127)) &~(x)& (((x)&~0ULL/255*127)+~0ULL/255*(127-(m))) )&~0ULL/255*128);\n    }\n\n    static inline bool notFieldNameWord(uint64_t x) {\n        return hasLess(x, '-') |\n        hasBetween(x, '-', '0') |\n        hasBetween(x, '9', 'A') |\n        hasBetween(x, 'Z', 'a') |\n        hasMore(x, 'z');\n    }\n\n    /* RFC 9110 5.6.2. Tokens */\n    /* Hyphen is not checked here as it is very common */\n    static inline bool isUnlikelyFieldNameByte(unsigned char c)\n    {\n        /* Digits and 14 of the 15 non-alphanum characters (lacking hyphen) */\n        return ((c == '~') | (c == '|') | (c == '`') | (c == '_') | (c == '^') | (c == '.') | (c == '+')\n            | (c == '*') | (c == '!')) || ((c >= 48) & (c <= 57)) || ((c <= 39) & (c >= 35));\n    }\n\n    static inline bool isFieldNameByteFastLowercased(unsigned char &in) {\n        /* Most common is lowercase alpha and hyphen */\n        if (((in >= 97) & (in <= 122)) | (in == '-')) [[likely]] {\n            return true;\n        /* Second is upper case alpha */\n        } else if ((in >= 65) & (in <= 90)) [[unlikely]] {\n            in |= 32;\n            return true;\n        /* These are rarely used but still valid */\n        } else if (isUnlikelyFieldNameByte(in)) [[unlikely]] {\n            return true;\n        }\n        return false;\n    }\n    \n    static inline void *consumeFieldName(char *p) {\n        /* Best case fast path (particularly useful with clang) */\n        while (true) {\n            while ((*p >= 65) & (*p <= 90)) [[likely]] {\n                *p |= 32;\n                p++;\n            }\n            while (((*p >= 97) & (*p <= 122))) [[likely]] {\n                p++;\n            }\n            if (*p == ':') {\n                return (void *)p;\n            }\n            if (*p == '-') {\n                p++;\n            } else if (!((*p >= 65) & (*p <= 90))) {\n                /* Exit fast path parsing */\n                break;\n            }\n        }\n\n        /* Generic */\n        while (isFieldNameByteFastLowercased(*(unsigned char *)p)) {\n            p++;\n        }\n        return (void *)p;\n    }\n\n    /* Puts method as key, target as value and returns non-null (or nullptr on error). */\n    static inline char *consumeRequestLine(char *data, char *end, HttpRequest::Header &header) {\n        /* Scan until single SP, assume next is / (origin request) */\n        char *start = data;\n        /* This catches the post padded CR and fails */\n        while (data[0] > 32) data++;\n        if (&data[1] == end) [[unlikely]] {\n            return nullptr;\n        }\n        if (data[0] == 32 && data[1] == '/') [[likely]] {\n            header.key = {start, (size_t) (data - start)};\n            data++;\n            /* Scan for less than 33 (catches post padded CR and fails) */\n            start = data;\n            for (; true; data += 8) {\n                uint64_t word;\n                memcpy(&word, data, sizeof(uint64_t));\n                if (hasLess(word, 33)) {\n                    while (*(unsigned char *)data > 32) data++;\n                    /* Now we stand on space */\n                    header.value = {start, (size_t) (data - start)};\n                    /* Check that the following is http 1.1 */\n                    if (data + 11 >= end) {\n                        /* Whatever we have must be part of the version string */\n                        if (memcmp(\" HTTP/1.1\\r\\n\", data, std::min<unsigned int>(11, (unsigned int) (end - data))) == 0) {\n                            return nullptr;\n                        }\n                        return (char *) 0x1;\n                    }\n                    if (memcmp(\" HTTP/1.1\\r\\n\", data, 11) == 0) {\n                        return data + 11;\n                    }\n                    /* If we stand at the post padded CR, we have fragmented input so try again later */\n                    if (data[0] == '\\r') {\n                        return nullptr;\n                    }\n                    /* This is an error */\n                    return (char *) 0x1;\n                }\n            }\n        }\n        /* If we stand at the post padded CR, we have fragmented input so try again later */\n        if (data[0] == '\\r') {\n            return nullptr;\n        }\n        return (char *) 0x1;\n    }\n\n    /* RFC 9110: 5.5 Field Values (TLDR; anything above 31 is allowed; htab (9) is also allowed)\n     * Field values are usually constrained to the range of US-ASCII characters [...]\n     * Field values containing CR, LF, or NUL characters are invalid and dangerous [...]\n     * Field values containing other CTL characters are also invalid. */\n    static inline void *tryConsumeFieldValue(char *p) {\n        for (; true; p += 8) {\n            uint64_t word;\n            memcpy(&word, p, sizeof(uint64_t));\n            if (hasLess(word, 32)) {\n                while (*(unsigned char *)p > 31) p++;\n                return (void *)p;\n            }\n        }\n    }\n\n    /* End is only used for the proxy parser. The HTTP parser recognizes \"\\ra\" as invalid \"\\r\\n\" scan and breaks. */\n    static unsigned int getHeaders(char *postPaddedBuffer, char *end, struct HttpRequest::Header *headers, void *reserved, unsigned int &err) {\n        char *preliminaryKey, *preliminaryValue, *start = postPaddedBuffer;\n\n        #ifdef UWS_WITH_PROXY\n            /* ProxyParser is passed as reserved parameter */\n            ProxyParser *pp = (ProxyParser *) reserved;\n\n            /* Parse PROXY protocol */\n            auto [done, offset] = pp->parse({postPaddedBuffer, (size_t) (end - postPaddedBuffer)});\n            if (!done) {\n                /* We do not reset the ProxyParser (on filure) since it is tied to this\n                * connection, which is really only supposed to ever get one PROXY frame\n                * anyways. We do however allow multiple PROXY frames to be sent (overwrites former). */\n                return 0;\n            } else {\n                /* We have consumed this data so skip it */\n                postPaddedBuffer += offset;\n            }\n        #else\n            /* This one is unused */\n            (void) reserved;\n            (void) end;\n        #endif\n\n        /* It is critical for fallback buffering logic that we only return with success\n         * if we managed to parse a complete HTTP request (minus data). Returning success\n         * for PROXY means we can end up succeeding, yet leaving bytes in the fallback buffer\n         * which is then removed, and our counters to flip due to overflow and we end up with a crash */\n\n        /* The request line is different from the field names / field values */\n        if ((char *) 2 > (postPaddedBuffer = consumeRequestLine(postPaddedBuffer, end, headers[0]))) {\n            /* Error - invalid request line */\n            /* Assuming it is 505 HTTP Version Not Supported */\n            err = postPaddedBuffer ? HTTP_ERROR_505_HTTP_VERSION_NOT_SUPPORTED : 0;\n            return 0;\n        }\n        headers++;\n\n        for (unsigned int i = 1; i < UWS_HTTP_MAX_HEADERS_COUNT - 1; i++) {\n            /* Lower case and consume the field name */\n            preliminaryKey = postPaddedBuffer;\n            postPaddedBuffer = (char *) consumeFieldName(postPaddedBuffer);\n            headers->key = std::string_view(preliminaryKey, (size_t) (postPaddedBuffer - preliminaryKey));\n\n            /* We should not accept whitespace between key and colon, so colon must foloow immediately */\n            if (postPaddedBuffer[0] != ':') {\n                /* If we stand at the end, we are fragmented */\n                if (postPaddedBuffer == end) {\n                    return 0;\n                }\n                /* Error: invalid chars in field name */\n                err = HTTP_ERROR_400_BAD_REQUEST;\n                return 0;\n            }\n            postPaddedBuffer++;\n\n            preliminaryValue = postPaddedBuffer;\n            /* The goal of this call is to find next \"\\r\\n\", or any invalid field value chars, fast */\n            while (true) {\n                postPaddedBuffer = (char *) tryConsumeFieldValue(postPaddedBuffer);\n                /* If this is not CR then we caught some stinky invalid char on the way */\n                if (postPaddedBuffer[0] != '\\r') {\n                    /* If TAB then keep searching */\n                    if (postPaddedBuffer[0] == '\\t') {\n                        postPaddedBuffer++;\n                        continue;\n                    }\n                    /* Error - invalid chars in field value */\n                    err = HTTP_ERROR_400_BAD_REQUEST;\n                    return 0;\n                }\n                break;\n            }\n            /* We fence end[0] with \\r, followed by end[1] being something that is \"not \\n\", to signify \"not found\".\n                * This way we can have this one single check to see if we found \\r\\n WITHIN our allowed search space. */\n            if (postPaddedBuffer[1] == '\\n') {\n                /* Store this header, it is valid */\n                headers->value = std::string_view(preliminaryValue, (size_t) (postPaddedBuffer - preliminaryValue));\n                postPaddedBuffer += 2;\n\n                /* Trim trailing whitespace (SP, HTAB) */\n                while (headers->value.length() && headers->value.back() < 33) {\n                    headers->value.remove_suffix(1);\n                }\n\n                /* Trim initial whitespace (SP, HTAB) */\n                while (headers->value.length() && headers->value.front() < 33) {\n                    headers->value.remove_prefix(1);\n                }\n                \n                headers++;\n\n                /* We definitely have at least one header (or request line), so check if we are done */\n                if (*postPaddedBuffer == '\\r') {\n                    if (postPaddedBuffer[1] == '\\n') {\n                        /* This cann take the very last header space */\n                        headers->key = std::string_view(nullptr, 0);\n                        return (unsigned int) ((postPaddedBuffer + 2) - start);\n                    } else {\n                        /* \\r\\n\\r plus non-\\n letter is malformed request, or simply out of search space */\n                        if (postPaddedBuffer + 1 < end) {\n                            err = HTTP_ERROR_400_BAD_REQUEST;\n                        }\n                        return 0;\n                    }\n                }\n            } else {\n                /* We are either out of search space or this is a malformed request */\n                return 0;\n            }\n        }\n        /* We ran out of header space, too large request */\n        err = HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE;\n        return 0;\n    }\n\n    /* This is the only caller of getHeaders and is thus the deepest part of the parser.\n     * From here we return either [consumed, user] for \"keep going\",\n      * or [consumed, nullptr] for \"break; I am closed or upgraded to websocket\"\n      * or [whatever, fullptr] for \"break and close me, I am a parser error!\" */\n    template <int CONSUME_MINIMALLY>\n    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) {\n\n        /* How much data we CONSUMED (to throw away) */\n        unsigned int consumedTotal = 0;\n        unsigned int err = 0;\n\n        /* Fence two bytes past end of our buffer (buffer has post padded margins).\n         * This is to always catch scan for \\r but not for \\r\\n. */\n        data[length] = '\\r';\n        data[length + 1] = 'a'; /* Anything that is not \\n, to trigger \"invalid request\" */\n\n        for (unsigned int consumed; length && (consumed = getHeaders(data, data + length, req->headers, reserved, err)); ) {\n            data += consumed;\n            length -= consumed;\n            consumedTotal += consumed;\n\n            /* Even if we could parse it, check for length here as well */\n            if (consumed > MAX_FALLBACK_SIZE) {\n                return {HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE, FULLPTR};\n            }\n\n            /* Store HTTP version (ancient 1.0 or 1.1) */\n            req->ancientHttp = false;\n\n            /* Add all headers to bloom filter */\n            req->bf.reset();\n            for (HttpRequest::Header *h = req->headers; (++h)->key.length(); ) {\n                if (req->bf.mightHave(h->key)) [[unlikely]] {\n                    /* Host header is not allowed twice */\n                    if (h->key == \"host\" && req->getHeader(\"host\").data()) {\n                        return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};\n                    }\n                }\n                req->bf.add(h->key);\n            }\n            \n            /* Break if no host header (but we can have empty string which is different from nullptr) */\n            if (!req->getHeader(\"host\").data()) {\n                return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};\n            }\n\n            /* RFC 9112 6.3\n            * If a message is received with both a Transfer-Encoding and a Content-Length header field,\n            * the Transfer-Encoding overrides the Content-Length. Such a message might indicate an attempt\n            * to perform request smuggling (Section 11.2) or response splitting (Section 11.1) and\n            * ought to be handled as an error. */\n            std::string_view transferEncodingString = req->getHeader(\"transfer-encoding\");\n            std::string_view contentLengthString = req->getHeader(\"content-length\");\n            if (transferEncodingString.length() && contentLengthString.length()) {\n                /* Returning fullptr is the same as calling the errorHandler */\n                /* We could be smart and set an error in the context along with this, to indicate what \n                 * http error response we might want to return */\n                return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};\n            }\n\n            /* Parse query */\n            const char *querySeparatorPtr = (const char *) memchr(req->headers->value.data(), '?', req->headers->value.length());\n            req->querySeparator = (unsigned int) ((querySeparatorPtr ? querySeparatorPtr : req->headers->value.data() + req->headers->value.length()) - req->headers->value.data());\n\n            /* If returned socket is not what we put in we need\n             * to break here as we either have upgraded to\n             * WebSockets or otherwise closed the socket. */\n            void *returnedUser = requestHandler(user, req);\n            if (returnedUser != user) {\n                /* We are upgraded to WebSocket or otherwise broken */\n                return {consumedTotal, returnedUser};\n            }\n\n            /* The rules at play here according to RFC 9112 for requests are essentially:\n             * If both content-length and transfer-encoding then invalid message; must break.\n             * If has transfer-encoding then must be chunked regardless of value.\n             * If content-length then fixed length even if 0.\n             * If none of the above then fixed length is 0. */\n\n            /* RFC 9112 6.3\n             * If a message is received with both a Transfer-Encoding and a Content-Length header field,\n             * the Transfer-Encoding overrides the Content-Length. */\n            if (transferEncodingString.length()) {\n\n                /* If a proxy sent us the transfer-encoding header that 100% means it must be chunked or else the proxy is\n                 * not RFC 9112 compliant. Therefore it is always better to assume this is the case, since that entirely eliminates \n                 * all forms of transfer-encoding obfuscation tricks. We just rely on the header. */\n\n                /* RFC 9112 6.3\n                 * If a Transfer-Encoding header field is present in a request and the chunked transfer coding is not the\n                 * final encoding, the message body length cannot be determined reliably; the server MUST respond with the\n                 * 400 (Bad Request) status code and then close the connection. */\n\n                /* In this case we fail later by having the wrong interpretation (assuming chunked).\n                 * This could be made stricter but makes no difference either way, unless forwarding the identical message as a proxy. */\n\n                remainingStreamingBytes = STATE_IS_CHUNKED;\n                /* If consume minimally, we do not want to consume anything but we want to mark this as being chunked */\n                if (!CONSUME_MINIMALLY) {\n                    /* Go ahead and parse it (todo: better heuristics for emitting FIN to the app level) */\n                    std::string_view dataToConsume(data, length);\n                    for (auto chunk : uWS::ChunkIterator(&dataToConsume, &remainingStreamingBytes)) {\n                        dataHandler(user, chunk, chunk.length() == 0);\n                    }\n                    if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) {\n                        return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};\n                    }\n                    unsigned int consumed = (length - (unsigned int) dataToConsume.length());\n                    data = (char *) dataToConsume.data();\n                    length = (unsigned int) dataToConsume.length();\n                    consumedTotal += consumed;\n                }\n            } else if (contentLengthString.length()) {\n                remainingStreamingBytes = toUnsignedInteger(contentLengthString);\n                if (remainingStreamingBytes == UINT64_MAX) {\n                    /* Parser error */\n                    return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};\n                }\n\n                if (!CONSUME_MINIMALLY) {\n                    unsigned int emittable = (unsigned int) std::min<uint64_t>(remainingStreamingBytes, length);\n                    dataHandler(user, std::string_view(data, emittable), emittable == remainingStreamingBytes);\n                    remainingStreamingBytes -= emittable;\n\n                    data += emittable;\n                    length -= emittable;\n                    consumedTotal += emittable;\n                }\n            } else {\n                /* If we came here without a body; emit an empty data chunk to signal no data */\n                dataHandler(user, {}, true);\n            }\n\n            /* Consume minimally should break as easrly as possible */\n            if (CONSUME_MINIMALLY) {\n                break;\n            }\n        }\n        /* Whenever we return FULLPTR, the interpretation of \"consumed\" should be the HttpError enum. */\n        if (err) {\n            return {err, FULLPTR};\n        }\n        return {consumedTotal, user};\n    }\n\npublic:\n    /* Returns the remaining body length if set via content-length, UINT64_MAX if transfer-encoding is chunked, or 0 if no body */\n    uint64_t maxRemainingBodyLength() {\n        if (isParsingChunkedEncoding(remainingStreamingBytes)) {\n            return UINT64_MAX;\n        }\n        return remainingStreamingBytes;\n    }\n\n    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) {\n\n        /* This resets BloomFilter by construction, but later we also reset it again.\n         * Optimize this to skip resetting twice (req could be made global) */\n        HttpRequest req;\n\n        if (remainingStreamingBytes) {\n\n            /* It's either chunked or with a content-length */\n            if (isParsingChunkedEncoding(remainingStreamingBytes)) {\n                std::string_view dataToConsume(data, length);\n                for (auto chunk : uWS::ChunkIterator(&dataToConsume, &remainingStreamingBytes)) {\n                    dataHandler(user, chunk, chunk.length() == 0);\n                }\n                if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) {\n                    return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};\n                }\n                data = (char *) dataToConsume.data();\n                length = (unsigned int) dataToConsume.length();\n            } else {\n                // this is exactly the same as below!\n                // todo: refactor this\n                if (remainingStreamingBytes >= length) {\n                    void *returnedUser = dataHandler(user, std::string_view(data, length), remainingStreamingBytes == length);\n                    remainingStreamingBytes -= length;\n                    return {0, returnedUser};\n                } else {\n                    void *returnedUser = dataHandler(user, std::string_view(data, remainingStreamingBytes), true);\n\n                    data += (unsigned int) remainingStreamingBytes;\n                    length -= (unsigned int) remainingStreamingBytes;\n\n                    remainingStreamingBytes = 0;\n\n                    if (returnedUser != user) {\n                        return {0, returnedUser};\n                    }\n                }\n            }\n\n        } else if (fallback.length()) {\n            unsigned int had = (unsigned int) fallback.length();\n\n            size_t maxCopyDistance = std::min<size_t>(MAX_FALLBACK_SIZE - fallback.length(), (size_t) length);\n\n            /* We don't want fallback to be short string optimized, since we want to move it */\n            fallback.reserve(fallback.length() + maxCopyDistance + std::max<unsigned int>(MINIMUM_HTTP_POST_PADDING, sizeof(std::string)));\n            fallback.append(data, maxCopyDistance);\n\n            // break here on break\n            std::pair<unsigned int, void *> consumed = fenceAndConsumePostPadded<true>(fallback.data(), (unsigned int) fallback.length(), user, reserved, &req, requestHandler, dataHandler);\n            if (consumed.second != user) {\n                return consumed;\n            }\n\n            if (consumed.first) {\n\n                /* This logic assumes that we consumed everything in fallback buffer.\n                 * This is critically important, as we will get an integer overflow in case\n                 * of \"had\" being larger than what we consumed, and that we would drop data */\n                fallback.clear();\n                data += consumed.first - had;\n                length -= consumed.first - had;\n\n                if (remainingStreamingBytes) {\n                    /* It's either chunked or with a content-length */\n                    if (isParsingChunkedEncoding(remainingStreamingBytes)) {\n                        std::string_view dataToConsume(data, length);\n                        for (auto chunk : uWS::ChunkIterator(&dataToConsume, &remainingStreamingBytes)) {\n                            dataHandler(user, chunk, chunk.length() == 0);\n                        }\n                        if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) {\n                            return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR};\n                        }\n                        data = (char *) dataToConsume.data();\n                        length = (unsigned int) dataToConsume.length();\n                    } else {\n                        // this is exactly the same as above!\n                        if (remainingStreamingBytes >= (unsigned int) length) {\n                            void *returnedUser = dataHandler(user, std::string_view(data, length), remainingStreamingBytes == (unsigned int) length);\n                            remainingStreamingBytes -= length;\n                            return {0, returnedUser};\n                        } else {\n                            void *returnedUser = dataHandler(user, std::string_view(data, remainingStreamingBytes), true);\n\n                            data += (unsigned int) remainingStreamingBytes;\n                            length -= (unsigned int) remainingStreamingBytes;\n\n                            remainingStreamingBytes = 0;\n\n                            if (returnedUser != user) {\n                                return {0, returnedUser};\n                            }\n                        }\n                    }\n                }\n\n            } else {\n                if (fallback.length() == MAX_FALLBACK_SIZE) {\n                    return {HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE, FULLPTR};\n                }\n                return {0, user};\n            }\n        }\n\n        std::pair<unsigned int, void *> consumed = fenceAndConsumePostPadded<false>(data, length, user, reserved, &req, requestHandler, dataHandler);\n        if (consumed.second != user) {\n            return consumed;\n        }\n\n        data += consumed.first;\n        length -= consumed.first;\n\n        if (length) {\n            if (length < MAX_FALLBACK_SIZE) {\n                fallback.append(data, length);\n            } else {\n                return {HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE, FULLPTR};\n            }\n        }\n\n        // added for now\n        return {0, user};\n    }\n};\n\n}\n\n#endif // UWS_HTTPPARSER_H\n"
  },
  {
    "path": "src/HttpResponse.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2025.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef UWS_HTTPRESPONSE_H\n#define UWS_HTTPRESPONSE_H\n\n/* An HttpResponse is the channel on which you send back a response */\n\n#include \"AsyncSocket.h\"\n#include \"HttpResponseData.h\"\n#include \"HttpContext.h\"\n#include \"HttpContextData.h\"\n#include \"Utilities.h\"\n\n#include \"WebSocketExtensions.h\"\n#include \"WebSocketHandshake.h\"\n#include \"WebSocket.h\"\n#include \"WebSocketContextData.h\"\n\n#include \"MoveOnlyFunction.h\"\n\n/* todo: tryWrite is missing currently, only send smaller segments with write */\n\nnamespace uWS {\n\n/* Some pre-defined status constants to use with writeStatus */\nstatic const char *HTTP_200_OK = \"200 OK\";\n\n/* The general timeout for HTTP sockets */\nstatic const int HTTP_TIMEOUT_S = 10;\n\ntemplate <bool SSL>\nstruct HttpResponse : public AsyncSocket<SSL> {\n    /* Solely used for getHttpResponseData() */\n    template <bool> friend struct TemplatedApp;\n    typedef AsyncSocket<SSL> Super;\nprivate:\n    HttpResponseData<SSL> *getHttpResponseData() {\n        return (HttpResponseData<SSL> *) Super::getAsyncSocketData();\n    }\n\n    /* Write an unsigned 32-bit integer in hex */\n    void writeUnsignedHex(unsigned int value) {\n        /* Buf really only needs to be 8 long but building with\n         * -mavx2, GCC still wants to overstep it so made it 16 */\n        char buf[16];\n        int length = utils::u32toaHex(value, buf);\n\n        /* For now we do this copy */\n        Super::write(buf, length);\n    }\n\n    /* Write an unsigned 64-bit integer */\n    void writeUnsigned64(uint64_t value) {\n        char buf[20];\n        int length = utils::u64toa(value, buf);\n\n        /* For now we do this copy */\n        Super::write(buf, length);\n    }\n\n    /* Called only once per request */\n    void writeMark() {\n        /* Date is always written */\n        writeHeader(\"Date\", std::string_view(((LoopData *) us_loop_ext(us_socket_context_loop(SSL, (us_socket_context(SSL, (us_socket_t *) this)))))->date, 29));\n\n        /* You can disable this altogether */\n#ifndef UWS_HTTPRESPONSE_NO_WRITEMARK\n        if (!Super::getLoopData()->noMark) {\n            /* We only expose major version */\n            writeHeader(\"uWebSockets\", \"20\");\n        }\n#endif\n    }\n\n    /* Returns true on success, indicating that it might be feasible to write more data.\n     * Will start timeout if stream reaches totalSize or write failure. */\n    bool internalEnd(std::string_view data, uintmax_t totalSize, bool optional, bool allowContentLength = true, bool closeConnection = false) {\n        /* Write status if not already done */\n        writeStatus(HTTP_200_OK);\n\n        /* If no total size given then assume this chunk is everything */\n        if (!totalSize) {\n            totalSize = data.length();\n        }\n\n        HttpResponseData<SSL> *httpResponseData = getHttpResponseData();\n\n        /* In some cases, such as when refusing huge data we want to close the connection when drained */\n        if (closeConnection) {\n\n            /* HTTP 1.1 must send this back unless the client already sent it to us.\n             * It is a connection close when either of the two parties say so but the\n             * one party must tell the other one so.\n             *\n             * This check also serves to limit writing the header only once. */\n            if ((httpResponseData->state & HttpResponseData<SSL>::HTTP_CONNECTION_CLOSE) == 0) {\n                writeHeader(\"Connection\", \"close\");\n            }\n\n            httpResponseData->state |= HttpResponseData<SSL>::HTTP_CONNECTION_CLOSE;\n        }\n\n        if (httpResponseData->state & HttpResponseData<SSL>::HTTP_WRITE_CALLED) {\n\n            /* We do not have tryWrite-like functionalities, so ignore optional in this path */\n\n            /* Do not allow sending 0 chunk here */\n            if (data.length()) {\n                Super::write(\"\\r\\n\", 2);\n                writeUnsignedHex((unsigned int) data.length());\n                Super::write(\"\\r\\n\", 2);\n\n                /* Ignoring optional for now */\n                Super::write(data.data(), (int) data.length());\n            }\n\n            /* Terminating 0 chunk */\n            Super::write(\"\\r\\n0\\r\\n\\r\\n\", 7);\n\n            httpResponseData->markDone();\n\n            /* We need to check if we should close this socket here now */\n            if (!Super::isCorked()) {\n                if (httpResponseData->state & HttpResponseData<SSL>::HTTP_CONNECTION_CLOSE) {\n                    if ((httpResponseData->state & HttpResponseData<SSL>::HTTP_RESPONSE_PENDING) == 0) {\n                        if (((AsyncSocket<SSL> *) this)->getBufferedAmount() == 0) {\n                            ((AsyncSocket<SSL> *) this)->shutdown();\n                            /* We need to force close after sending FIN since we want to hinder\n                                * clients from keeping to send their huge data */\n                            ((AsyncSocket<SSL> *) this)->close();\n                            return true;\n                        }\n                    }\n                }\n            }\n\n            /* tryEnd can never fail when in chunked mode, since we do not have tryWrite (yet), only write */\n            Super::timeout(HTTP_TIMEOUT_S);\n            return true;\n        } else {\n            /* Write content-length on first call */\n            if (!(httpResponseData->state & HttpResponseData<SSL>::HTTP_END_CALLED)) {\n                /* Write mark, this propagates to WebSockets too */\n                writeMark();\n\n                /* WebSocket upgrades does not allow content-length */\n                if (allowContentLength) {\n                    /* Even zero is a valid content-length */\n                    Super::write(\"Content-Length: \", 16);\n                    writeUnsigned64(totalSize);\n                    Super::write(\"\\r\\n\\r\\n\", 4);\n                } else {\n                    Super::write(\"\\r\\n\", 2);\n                }\n\n                /* Mark end called */\n                httpResponseData->state |= HttpResponseData<SSL>::HTTP_END_CALLED;\n            }\n\n            /* Even if we supply no new data to write, its failed boolean is useful to know\n             * if it failed to drain any prior failed header writes */\n\n            /* Write as much as possible without causing backpressure */\n            size_t written = 0;\n            bool failed = false;\n            while (written < data.length() && !failed) {\n                /* uSockets only deals with int sizes, so pass chunks of max signed int size */\n                auto writtenFailed = Super::write(data.data() + written, (int) std::min<size_t>(data.length() - written, INT_MAX), optional);\n\n                written += (size_t) writtenFailed.first;\n                failed = writtenFailed.second;\n            }\n\n            httpResponseData->offset += written;\n\n            /* Success is when we wrote the entire thing without any failures */\n            bool success = written == data.length() && !failed;\n\n            /* If we are now at the end, start a timeout. Also start a timeout if we failed. */\n            if (!success || httpResponseData->offset == totalSize) {\n                Super::timeout(HTTP_TIMEOUT_S);\n            }\n\n            /* Remove onAborted, onWritable function and mark done if we reach the end, or if we were given no data (faked size like in HEAD response) */\n            /* I need to figure out if this line should rather be simply httpResponseData->offset == data.length() */\n            /* No that can't be right, tryEnd with fake length should not complete the response even if the smaller chunk wrote in one go */\n            /* Possibly need  to separate endWithoutBody and tryEnd with fake length into two separate calls with a boolean that explicitly marks isHeadOnly */\n            if (httpResponseData->offset == totalSize || !data.length()) {\n                httpResponseData->markDone();\n\n                /* We need to check if we should close this socket here now */\n                if (!Super::isCorked()) {\n                    if (httpResponseData->state & HttpResponseData<SSL>::HTTP_CONNECTION_CLOSE) {\n                        if ((httpResponseData->state & HttpResponseData<SSL>::HTTP_RESPONSE_PENDING) == 0) {\n                            if (((AsyncSocket<SSL> *) this)->getBufferedAmount() == 0) {\n                                ((AsyncSocket<SSL> *) this)->shutdown();\n                                /* We need to force close after sending FIN since we want to hinder\n                                * clients from keeping to send their huge data */\n                                ((AsyncSocket<SSL> *) this)->close();\n                            }\n                        }\n                    }\n                }\n            }\n\n            return success;\n        }\n    }\n\npublic:\n    /* If we have proxy support; returns the proxed source address as reported by the proxy. */\n#ifdef UWS_WITH_PROXY\n    std::string_view getProxiedRemoteAddress() {\n        return getHttpResponseData()->proxyParser.getSourceAddress();\n    }\n\n    std::string_view getProxiedRemoteAddressAsText() {\n        return Super::addressAsText(getProxiedRemoteAddress());\n    }\n\n    unsigned int getProxiedRemotePort() {\n        return getHttpResponseData()->proxyParser.getSourcePort();\n    }\n#endif\n\n    /* Manually upgrade to WebSocket. Typically called in upgrade handler. Immediately calls open handler.\n     * NOTE: Will invalidate 'this' as socket might change location in memory. Throw away after use. */\n    template <typename UserData>\n    void upgrade(UserData &&userData, std::string_view secWebSocketKey, std::string_view secWebSocketProtocol,\n            std::string_view secWebSocketExtensions,\n            struct us_socket_context_t *webSocketContext) {\n\n        /* Extract needed parameters from WebSocketContextData */\n        WebSocketContextData<SSL, UserData> *webSocketContextData = (WebSocketContextData<SSL, UserData> *) us_socket_context_ext(SSL, webSocketContext);\n\n        /* Note: OpenSSL can be used here to speed this up somewhat */\n        char secWebSocketAccept[29] = {};\n        WebSocketHandshake::generate(secWebSocketKey.data(), secWebSocketAccept);\n\n        writeStatus(\"101 Switching Protocols\")\n            ->writeHeader(\"Upgrade\", \"websocket\")\n            ->writeHeader(\"Connection\", \"Upgrade\")\n            ->writeHeader(\"Sec-WebSocket-Accept\", secWebSocketAccept);\n\n        /* Select first subprotocol if present */\n        if (secWebSocketProtocol.length()) {\n            writeHeader(\"Sec-WebSocket-Protocol\", secWebSocketProtocol.substr(0, secWebSocketProtocol.find(',')));\n        }\n\n        /* Negotiate compression */\n        bool perMessageDeflate = false;\n        CompressOptions compressOptions = CompressOptions::DISABLED;\n        if (secWebSocketExtensions.length() && webSocketContextData->compression != DISABLED) {\n\n            /* Make sure to map SHARED_DECOMPRESSOR to windowBits = 0, not 1  */\n            int wantedInflationWindow = 0;\n            if ((webSocketContextData->compression & CompressOptions::_DECOMPRESSOR_MASK) != CompressOptions::SHARED_DECOMPRESSOR) {\n                wantedInflationWindow = (webSocketContextData->compression & CompressOptions::_DECOMPRESSOR_MASK) >> 8;\n            }\n\n            /* Map from selected compressor (this automatically maps SHARED_COMPRESSOR to windowBits 0, not 1) */\n            int wantedCompressionWindow = (webSocketContextData->compression & CompressOptions::_COMPRESSOR_MASK) >> 4;\n\n            auto [negCompression, negCompressionWindow, negInflationWindow, negResponse] =\n            negotiateCompression(true, wantedCompressionWindow, wantedInflationWindow,\n                                        secWebSocketExtensions);\n\n            if (negCompression) {\n                perMessageDeflate = true;\n\n                /* Map from negotiated windowBits to compressor and decompressor */\n                if (negCompressionWindow == 0) {\n                    compressOptions = CompressOptions::SHARED_COMPRESSOR;\n                } else {\n                    compressOptions = (CompressOptions) ((uint32_t) (negCompressionWindow << 4)\n                                                        | (uint32_t) (negCompressionWindow - 7));\n\n                    /* If we are dedicated and have the 3kb then correct any 4kb to 3kb,\n                     * (they both share the windowBits = 9) */\n                    if (webSocketContextData->compression & DEDICATED_COMPRESSOR_3KB) {\n                        compressOptions = DEDICATED_COMPRESSOR_3KB;\n                    }\n                }\n\n                /* Here we modify the above compression with negotiated decompressor */\n                if (negInflationWindow == 0) {\n                    compressOptions = CompressOptions(compressOptions | CompressOptions::SHARED_DECOMPRESSOR);\n                } else {\n                    compressOptions = CompressOptions(compressOptions | (negInflationWindow << 8));\n                }\n\n                writeHeader(\"Sec-WebSocket-Extensions\", negResponse);\n            }\n        }\n\n        internalEnd({nullptr, 0}, 0, false, false);\n\n        /* Grab the httpContext from res */\n        HttpContext<SSL> *httpContext = (HttpContext<SSL> *) us_socket_context(SSL, (struct us_socket_t *) this);\n\n        /* Move any backpressure out of HttpResponse */\n        BackPressure backpressure(std::move(((AsyncSocketData<SSL> *) getHttpResponseData())->buffer));\n\n        /* Destroy HttpResponseData */\n        getHttpResponseData()->~HttpResponseData();\n\n        /* Before we adopt and potentially change socket, check if we are corked */\n        bool wasCorked = Super::isCorked();\n\n        /* Adopting a socket invalidates it, do not rely on it directly to carry any data */\n        WebSocket<SSL, true, UserData> *webSocket = (WebSocket<SSL, true, UserData> *) us_socket_context_adopt_socket(SSL,\n                    (us_socket_context_t *) webSocketContext, (us_socket_t *) this, sizeof(WebSocketData) + sizeof(UserData));\n\n        /* For whatever reason we were corked, update cork to the new socket */\n        if (wasCorked) {\n            webSocket->AsyncSocket<SSL>::corkUnchecked();\n        }\n\n        /* Initialize websocket with any moved backpressure intact */\n        webSocket->init(perMessageDeflate, compressOptions, std::move(backpressure));\n\n        /* We should only mark this if inside the parser; if upgrading \"async\" we cannot set this */\n        HttpContextData<SSL> *httpContextData = httpContext->getSocketContextData();\n        if (httpContextData->isParsingHttp) {\n            /* We need to tell the Http parser that we changed socket */\n            httpContextData->upgradedWebSocket = webSocket;\n        }\n\n        /* Arm maxLifetime timeout */\n        us_socket_long_timeout(SSL, (us_socket_t *) webSocket, webSocketContextData->maxLifetime);\n\n        /* Arm idleTimeout */\n        us_socket_timeout(SSL, (us_socket_t *) webSocket, webSocketContextData->idleTimeoutComponents.first);\n\n        /* Move construct the UserData right before calling open handler */\n        new (webSocket->getUserData()) UserData(std::move(userData));\n\n        /* Emit open event and start the timeout */\n        if (webSocketContextData->openHandler) {\n            webSocketContextData->openHandler(webSocket);\n        }\n    }\n\n    /* Immediately terminate this Http response */\n    using Super::close;\n\n    /* See AsyncSocket */\n    using Super::getRemoteAddress;\n    using Super::getRemoteAddressAsText;\n    using Super::getRemotePort;\n    using Super::getNativeHandle;\n\n    /* Throttle reads and writes */\n    HttpResponse *pause() {\n        Super::pause();\n        Super::timeout(0);\n        return this;\n    }\n\n    HttpResponse *resume() {\n        Super::resume();\n        Super::timeout(HTTP_TIMEOUT_S);\n        return this;\n    }\n\n    /* Note: Headers are not checked in regards to timeout.\n     * We only check when you actively push data or end the request */\n\n    /* Write 100 Continue, can be done any amount of times */\n    HttpResponse *writeContinue() {\n        Super::write(\"HTTP/1.1 100 Continue\\r\\n\\r\\n\", 25);\n        return this;\n    }\n\n    /* Write the HTTP status */\n    HttpResponse *writeStatus(std::string_view status) {\n        HttpResponseData<SSL> *httpResponseData = getHttpResponseData();\n\n        /* Do not allow writing more than one status */\n        if (httpResponseData->state & HttpResponseData<SSL>::HTTP_STATUS_CALLED) {\n            return this;\n        }\n\n        /* Update status */\n        httpResponseData->state |= HttpResponseData<SSL>::HTTP_STATUS_CALLED;\n\n        Super::write(\"HTTP/1.1 \", 9);\n        Super::write(status.data(), (int) status.length());\n        Super::write(\"\\r\\n\", 2);\n        return this;\n    }\n\n    /* Write an HTTP header with string value */\n    HttpResponse *writeHeader(std::string_view key, std::string_view value) {\n        writeStatus(HTTP_200_OK);\n\n        Super::write(key.data(), (int) key.length());\n        Super::write(\": \", 2);\n        Super::write(value.data(), (int) value.length());\n        Super::write(\"\\r\\n\", 2);\n        return this;\n    }\n\n    /* Write an HTTP header with unsigned int value */\n    HttpResponse *writeHeader(std::string_view key, uint64_t value) {\n        writeStatus(HTTP_200_OK);\n\n        Super::write(key.data(), (int) key.length());\n        Super::write(\": \", 2);\n        writeUnsigned64(value);\n        Super::write(\"\\r\\n\", 2);\n        return this;\n    }\n\n    /* End without a body (no content-length) or end with a spoofed content-length. */\n    void endWithoutBody(std::optional<size_t> reportedContentLength = std::nullopt, bool closeConnection = false) {\n        if (reportedContentLength.has_value()) {\n            internalEnd({nullptr, 0}, reportedContentLength.value(), false, true, closeConnection);\n        } else {\n            internalEnd({nullptr, 0}, 0, false, false, closeConnection);\n        }\n    }\n\n    /* End the response with an optional data chunk. Always starts a timeout. */\n    void end(std::string_view data = {}, bool closeConnection = false) {\n        internalEnd(data, data.length(), false, true, closeConnection);\n    }\n\n    /* Try and end the response. Returns [true, true] on success.\n     * Starts a timeout in some cases. Returns [ok, hasResponded] */\n    std::pair<bool, bool> tryEnd(std::string_view data, uintmax_t totalSize = 0, bool closeConnection = false) {\n        bool ok = internalEnd(data, totalSize, true, true, closeConnection);\n        return {ok, hasResponded()};\n    }\n\n    /* Write parts of the response in chunking fashion. Starts timeout if failed. */\n    bool write(std::string_view data) {\n        writeStatus(HTTP_200_OK);\n\n        /* Do not allow sending 0 chunks, they mark end of response */\n        if (!data.length()) {\n            /* If you called us, then according to you it was fine to call us so it's fine to still call us */\n            return true;\n        }\n\n        HttpResponseData<SSL> *httpResponseData = getHttpResponseData();\n\n        if (!(httpResponseData->state & HttpResponseData<SSL>::HTTP_WRITE_CALLED)) {\n            /* Write mark on first call to write */\n            writeMark();\n\n            writeHeader(\"Transfer-Encoding\", \"chunked\");\n            httpResponseData->state |= HttpResponseData<SSL>::HTTP_WRITE_CALLED;\n        }\n\n        Super::write(\"\\r\\n\", 2);\n        writeUnsignedHex((unsigned int) data.length());\n        Super::write(\"\\r\\n\", 2);\n\n        auto [written, failed] = Super::write(data.data(), (int) data.length());\n        if (failed) {\n            Super::timeout(HTTP_TIMEOUT_S);\n        }\n\n        /* If we did not fail the write, accept more */\n        return !failed;\n    }\n\n    /* Get the current byte write offset for this Http response */\n    uintmax_t getWriteOffset() {\n        HttpResponseData<SSL> *httpResponseData = getHttpResponseData();\n\n        return httpResponseData->offset;\n    }\n\n    /* Get the remaining body length if set via content-length, UINT64_MAX if transfer-encoding is chunked, or 0 if no body */\n    uint64_t maxRemainingBodyLength() {\n        HttpResponseData<SSL> *httpResponseData = getHttpResponseData();\n\n        return httpResponseData->maxRemainingBodyLength();\n    }\n\n    /* If you are messing around with sendfile you might want to override the offset. */\n    void overrideWriteOffset(uintmax_t offset) {\n        HttpResponseData<SSL> *httpResponseData = getHttpResponseData();\n\n        httpResponseData->offset = offset;\n    }\n\n    /* Checking if we have fully responded and are ready for another request */\n    bool hasResponded() {\n        HttpResponseData<SSL> *httpResponseData = getHttpResponseData();\n\n        return !(httpResponseData->state & HttpResponseData<SSL>::HTTP_RESPONSE_PENDING);\n    }\n\n    /* Corks the response if possible. Leaves already corked socket be. */\n    HttpResponse *cork(MoveOnlyFunction<void()> &&handler) {\n        if (!Super::isCorked() && Super::canCork()) {\n            LoopData *loopData = Super::getLoopData();\n            Super::cork();\n            handler();\n\n            /* The only way we could possibly have changed the corked socket during handler call, would be if \n             * the HTTP socket was upgraded to WebSocket and caused a realloc. Because of this we cannot use \"this\"\n             * from here downwards. The corking is done with corkUnchecked() in upgrade. It steals cork. */\n            auto *newCorkedSocket = loopData->corkedSocket;\n\n            /* If nobody is corked, it means most probably that large amounts of data has\n             * been written and the cork buffer has already been sent off and uncorked.\n             * We are done here, if that is the case. */\n            if (!newCorkedSocket) {\n                return this;\n            }\n\n            /* Timeout on uncork failure, since most writes will succeed while corked */\n            auto [written, failed] = static_cast<Super *>(newCorkedSocket)->uncork();\n\n            /* If we are no longer an HTTP socket then early return the new \"this\".\n             * We don't want to even overwrite timeout as it is set in upgrade already. */\n            if (this != newCorkedSocket) {\n                return static_cast<HttpResponse *>(newCorkedSocket);\n            }\n\n            if (failed) {\n                /* For now we only have one single timeout so let's use it */\n                /* This behavior should equal the behavior in HttpContext when uncorking fails */\n                Super::timeout(HTTP_TIMEOUT_S);\n            }\n\n            /* If we have no backbuffer and we are connection close and we responded fully then close */\n            HttpResponseData<SSL> *httpResponseData = getHttpResponseData();\n            if (httpResponseData->state & HttpResponseData<SSL>::HTTP_CONNECTION_CLOSE) {\n                if ((httpResponseData->state & HttpResponseData<SSL>::HTTP_RESPONSE_PENDING) == 0) {\n                    if (((AsyncSocket<SSL> *) this)->getBufferedAmount() == 0) {\n                        ((AsyncSocket<SSL> *) this)->shutdown();\n                        /* We need to force close after sending FIN since we want to hinder\n                        * clients from keeping to send their huge data */\n                        ((AsyncSocket<SSL> *) this)->close();\n                    }\n                }\n            }\n        } else {\n            /* We are already corked, or can't cork so let's just call the handler */\n            handler();\n        }\n\n        return this;\n    }\n\n    /* Attach handler for writable HTTP response */\n    HttpResponse *onWritable(MoveOnlyFunction<bool(uintmax_t)> &&handler) {\n        HttpResponseData<SSL> *httpResponseData = getHttpResponseData();\n\n        httpResponseData->onWritable = std::move(handler);\n        return this;\n    }\n\n    /* Attach handler for aborted HTTP request */\n    HttpResponse *onAborted(MoveOnlyFunction<void()> &&handler) {\n        HttpResponseData<SSL> *httpResponseData = getHttpResponseData();\n\n        httpResponseData->onAborted = std::move(handler);\n        return this;\n    }\n\n    /* Attach a read handler for data sent. Will be called with FIN set true if last segment. */\n    void onData(MoveOnlyFunction<void(std::string_view, bool)> &&handler) {\n        HttpResponseData<SSL> *data = getHttpResponseData();\n        data->inStream = std::move(handler);\n\n        /* Always reset this counter here */\n        data->received_bytes_per_timeout = 0;\n    }\n};\n\n}\n\n#endif // UWS_HTTPRESPONSE_H\n"
  },
  {
    "path": "src/HttpResponseData.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2020.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef UWS_HTTPRESPONSEDATA_H\n#define UWS_HTTPRESPONSEDATA_H\n\n/* This data belongs to the HttpResponse */\n\n#include \"HttpParser.h\"\n#include \"AsyncSocketData.h\"\n#include \"ProxyParser.h\"\n\n#include \"MoveOnlyFunction.h\"\n\nnamespace uWS {\n\ntemplate <bool SSL>\nstruct HttpResponseData : AsyncSocketData<SSL>, HttpParser {\n    template <bool> friend struct HttpResponse;\n    template <bool> friend struct HttpContext;\n\n    /* When we are done with a response we mark it like so */\n    void markDone() {\n        onAborted = nullptr;\n        /* Also remove onWritable so that we do not emit when draining behind the scenes. */\n        onWritable = nullptr;\n\n        /* We are done with this request */\n        state &= ~HttpResponseData<SSL>::HTTP_RESPONSE_PENDING;\n    }\n\n    /* Caller of onWritable. It is possible onWritable calls markDone so we need to borrow it. */\n    bool callOnWritable(uintmax_t offset) {\n        /* Borrow real onWritable */\n        MoveOnlyFunction<bool(uintmax_t)> borrowedOnWritable = std::move(onWritable);\n\n        /* Set onWritable to placeholder */\n        onWritable = [](uintmax_t) {return true;};\n\n        /* Run borrowed onWritable */\n        bool ret = borrowedOnWritable(offset);\n\n        /* If we still have onWritable (the placeholder) then move back the real one */\n        if (onWritable) {\n            /* We haven't reset onWritable, so give it back */\n            onWritable = std::move(borrowedOnWritable);\n        }\n\n        return ret;\n    }\nprivate:\n    /* Bits of status */\n    enum {\n        HTTP_STATUS_CALLED = 1, // used\n        HTTP_WRITE_CALLED = 2, // used\n        HTTP_END_CALLED = 4, // used\n        HTTP_RESPONSE_PENDING = 8, // used\n        HTTP_CONNECTION_CLOSE = 16 // used\n    };\n\n    /* Per socket event handlers */\n    MoveOnlyFunction<bool(uintmax_t)> onWritable;\n    MoveOnlyFunction<void()> onAborted;\n    MoveOnlyFunction<void(std::string_view, bool)> inStream; // onData\n    /* Outgoing offset */\n    uintmax_t offset = 0;\n\n    /* Let's track number of bytes since last timeout reset in data handler */\n    unsigned int received_bytes_per_timeout = 0;\n\n    /* Current state (content-length sent, status sent, write called, etc */\n    int state = 0;\n\n#ifdef UWS_WITH_PROXY\n    ProxyParser proxyParser;\n#endif\n};\n\n}\n\n#endif // UWS_HTTPRESPONSEDATA_H\n"
  },
  {
    "path": "src/HttpRouter.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2020.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef UWS_HTTPROUTER_HPP\n#define UWS_HTTPROUTER_HPP\n\n#include <map>\n#include <vector>\n#include <cstring>\n#include <string_view>\n#include <string>\n#include <algorithm>\n#include <memory>\n#include <utility>\n\n#include <iostream>\n\n#include \"MoveOnlyFunction.h\"\n\nnamespace uWS {\n\ntemplate <class USERDATA>\nstruct HttpRouter {\n    static constexpr std::string_view ANY_METHOD_TOKEN = \"*\";\n    static const uint32_t HIGH_PRIORITY = 0xd0000000, MEDIUM_PRIORITY = 0xe0000000, LOW_PRIORITY = 0xf0000000;\n\nprivate:\n    USERDATA userData;\n    static const unsigned int MAX_URL_SEGMENTS = 100;\n\n    /* Handler ids are 32-bit */\n    static const uint32_t HANDLER_MASK = 0x0fffffff;\n\n    /* List of handlers */\n    std::vector<MoveOnlyFunction<bool(HttpRouter *)>> handlers;\n\n    /* Current URL cache */\n    std::string_view currentUrl;\n    std::string_view urlSegmentVector[MAX_URL_SEGMENTS];\n    int urlSegmentTop;\n\n    /* The matching tree */\n    struct Node {\n        std::string name;\n        std::vector<std::unique_ptr<Node>> children;\n        std::vector<uint32_t> handlers;\n        bool isHighPriority;\n\n        Node(std::string name) : name(name) {}\n    } root = {\"rootNode\"};\n\n    /* Sort wildcards after alphanum */\n    int lexicalOrder(std::string &name) {\n        if (!name.length()) {\n            return 2;\n        }\n        if (name[0] == ':') {\n            return 1;\n        }\n        if (name[0] == '*') {\n            return 0;\n        }\n        return 2;\n    }\n\n    /* Advance from parent to child, adding child if necessary */\n    Node *getNode(Node *parent, std::string child, bool isHighPriority) {\n        for (std::unique_ptr<Node> &node : parent->children) {\n            if (node->name == child && node->isHighPriority == isHighPriority) {\n                return node.get();\n            }\n        }\n\n        /* Insert sorted, but keep order if parent is root (we sort methods by priority elsewhere) */\n        std::unique_ptr<Node> newNode(new Node(child));\n        newNode->isHighPriority = isHighPriority;\n        return parent->children.emplace(std::upper_bound(parent->children.begin(), parent->children.end(), newNode, [parent, this](auto &a, auto &b) {\n\n            if (a->isHighPriority != b->isHighPriority) {\n                return a->isHighPriority;\n            }\n\n            return b->name.length() && (parent != &root) && (lexicalOrder(b->name) < lexicalOrder(a->name));\n        }), std::move(newNode))->get();\n    }\n\n    /* Basically a pre-allocated stack */\n    struct RouteParameters {\n        friend struct HttpRouter;\n    private:\n        std::string_view params[MAX_URL_SEGMENTS];\n        int paramsTop;\n\n        void reset() {\n            paramsTop = -1;\n        }\n\n        void push(std::string_view param) {\n            /* We check these bounds indirectly via the urlSegments limit */\n            params[++paramsTop] = param;\n        }\n\n        void pop() {\n            /* Same here, we cannot pop outside */\n            paramsTop--;\n        }\n    } routeParameters;\n\n    /* Set URL for router. Will reset any URL cache */\n    inline void setUrl(std::string_view url) {\n\n        /* Todo: URL may also start with \"http://domain/\" or \"*\", not only \"/\" */\n\n        /* We expect to stand on a slash */\n        currentUrl = url;\n        urlSegmentTop = -1;\n    }\n\n    /* Lazily parse or read from cache */\n    inline std::pair<std::string_view, bool> getUrlSegment(int urlSegment) {\n        if (urlSegment > urlSegmentTop) {\n            /* Signal as STOP when we have no more URL or stack space */\n            if (!currentUrl.length() || urlSegment > int(MAX_URL_SEGMENTS - 1)) {\n                return {{}, true};\n            }\n\n            /* We always stand on a slash here, so step over it */\n            currentUrl.remove_prefix(1);\n\n            auto segmentLength = currentUrl.find('/');\n            if (segmentLength == std::string::npos) {\n                segmentLength = currentUrl.length();\n\n                /* Push to url segment vector */\n                urlSegmentVector[urlSegment] = currentUrl.substr(0, segmentLength);\n                urlSegmentTop++;\n\n                /* Update currentUrl */\n                currentUrl = currentUrl.substr(segmentLength);\n            } else {\n                /* Push to url segment vector */\n                urlSegmentVector[urlSegment] = currentUrl.substr(0, segmentLength);\n                urlSegmentTop++;\n\n                /* Update currentUrl */\n                currentUrl = currentUrl.substr(segmentLength);\n            }\n        }\n        /* In any case we return it */\n        return {urlSegmentVector[urlSegment], false};\n    }\n\n    /* Executes as many handlers it can */\n    bool executeHandlers(Node *parent, int urlSegment, USERDATA &userData) {\n\n        auto [segment, isStop] = getUrlSegment(urlSegment);\n\n        /* If we are on STOP, return where we may stand */\n        if (isStop) {\n            /* We have reached accross the entire URL with no stoppage, execute */\n            for (uint32_t handler : parent->handlers) {\n                if (handlers[handler & HANDLER_MASK](this)) {\n                    return true;\n                }\n            }\n            /* We reached the end, so go back */\n            return false;\n        }\n\n        for (auto &p : parent->children) {\n            if (p->name.length() && p->name[0] == '*') {\n                /* Wildcard match (can be seen as a shortcut) */\n                for (uint32_t handler : p->handlers) {\n                    if (handlers[handler & HANDLER_MASK](this)) {\n                        return true;\n                    }\n                }\n            } else if (p->name.length() && p->name[0] == ':' && segment.length()) {\n                /* Parameter match */\n                routeParameters.push(segment);\n                if (executeHandlers(p.get(), urlSegment + 1, userData)) {\n                    return true;\n                }\n                routeParameters.pop();\n            } else if (p->name == segment) {\n                /* Static match */\n                if (executeHandlers(p.get(), urlSegment + 1, userData)) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    /* Scans for one matching handler, returning the handler and its priority or UINT32_MAX for not found */\n    uint32_t findHandler(std::string method, std::string pattern, uint32_t priority) {\n        for (std::unique_ptr<Node> &node : root.children) {\n            if (method == node->name) {\n                setUrl(pattern);\n                Node *n = node.get();\n                for (int i = 0; !getUrlSegment(i).second; i++) {\n                    /* Go to next segment or quit */\n                    std::string segment = std::string(getUrlSegment(i).first);\n                    Node *next = nullptr;\n                    for (std::unique_ptr<Node> &child : n->children) {\n                        if (((segment.length() && child->name.length() && segment[0] == ':' && child->name[0] == ':') || child->name == segment) && child->isHighPriority == (priority == HIGH_PRIORITY)) {\n                            next = child.get();\n                            break;\n                        }\n                    }\n                    if (!next) {\n                        return UINT32_MAX;\n                    }\n                    n = next;\n                }\n                /* Seek for a priority match in the found node */\n                for (unsigned int i = 0; i < n->handlers.size(); i++) {\n                    if ((n->handlers[i] & ~HANDLER_MASK) == priority) {\n                        return n->handlers[i];\n                    }\n                }\n                return UINT32_MAX;\n            }\n        }\n        return UINT32_MAX;\n    }\n\npublic:\n    HttpRouter() {\n        /* Always have ANY route */\n        getNode(&root, std::string(ANY_METHOD_TOKEN.data(), ANY_METHOD_TOKEN.length()), false);\n    }\n\n    std::pair<int, std::string_view *> getParameters() {\n        return {routeParameters.paramsTop, routeParameters.params};\n    }\n\n    USERDATA &getUserData() {\n        return userData;\n    }\n\n    /* Fast path */\n    bool route(std::string_view method, std::string_view url) {\n        /* Reset url parsing cache */\n        setUrl(url);\n        routeParameters.reset();\n\n        /* Begin by finding the method node */\n        for (auto &p : root.children) {\n            if (p->name == method) {\n                /* Then route the url */\n                if (executeHandlers(p.get(), 0, userData)) {\n                    return true;\n                } else {\n                    break;\n                }\n            }\n        }\n\n        /* Always test any route last (this check should not be necessary if we always have at least one handler) */\n        if (root.children.empty()) [[unlikely]] {\n            return false;\n        }\n        return executeHandlers(root.children.back().get(), 0, userData);\n    }\n\n    /* Adds the corresponding entires in matching tree and handler list */\n    void add(std::vector<std::string> methods, std::string pattern, MoveOnlyFunction<bool(HttpRouter *)> &&handler, uint32_t priority = MEDIUM_PRIORITY) {\n        /* First remove existing handler */\n        remove(methods[0], pattern, priority);\n        \n        for (std::string method : methods) {\n            /* Lookup method */\n            Node *node = getNode(&root, method, false);\n            /* Iterate over all segments */\n            setUrl(pattern);\n            for (int i = 0; !getUrlSegment(i).second; i++) {\n                std::string strippedSegment(getUrlSegment(i).first);\n                if (strippedSegment.length() && strippedSegment[0] == ':') {\n                    /* Parameter routes must be named only : */\n                    strippedSegment = \":\";\n                }\n                node = getNode(node, strippedSegment, priority == HIGH_PRIORITY);\n            }\n            /* Insert handler in order sorted by priority (most significant 1 byte) */\n            node->handlers.insert(std::upper_bound(node->handlers.begin(), node->handlers.end(), (uint32_t) (priority | handlers.size())), (uint32_t) (priority | handlers.size()));\n        }\n\n        /* Alloate this handler */\n        handlers.emplace_back(std::move(handler));\n\n        /* ANY method must be last, GET must be first */\n        std::sort(root.children.begin(), root.children.end(), [](const auto &a, const auto &b) {\n            if (a->name == \"GET\" && b->name != \"GET\") {\n                return true;\n            } else if (b->name == \"GET\" && a->name != \"GET\") {\n                return false;\n            } else if (a->name == ANY_METHOD_TOKEN && b->name != ANY_METHOD_TOKEN) {\n                return false;\n            } else if (b->name == ANY_METHOD_TOKEN && a->name != ANY_METHOD_TOKEN) {\n                return true;\n            } else {\n                return a->name < b->name;\n            }\n        });\n    }\n\n    bool cullNode(Node *parent, Node *node, uint32_t handler) {\n        /* For all children */\n        for (unsigned int i = 0; i < node->children.size(); ) {\n            /* Optimization todo: only enter those with same isHighPrioirty */\n            /* Enter child so we get depth first */\n            if (!cullNode(node, node->children[i].get(), handler)) {\n                /* Only increase if this node was not removed */\n                i++;\n            }\n        }\n\n        /* Cull this node (but skip the root node) */\n        if (parent /*&& parent != &root*/) {\n            /* Scan for equal (remove), greater (lower by 1) */\n            for (auto it = node->handlers.begin(); it != node->handlers.end(); ) {\n                if ((*it & HANDLER_MASK) > (handler & HANDLER_MASK)) {\n                    *it = ((*it & HANDLER_MASK) - 1) | (*it & ~HANDLER_MASK);\n                } else if (*it == handler) {\n                    it = node->handlers.erase(it);\n                    continue;\n                }\n                it++;\n            }\n\n            /* If we have no children and no handlers, remove us from the parent->children list */\n            if (!node->handlers.size() && !node->children.size()) {\n                parent->children.erase(std::find_if(parent->children.begin(), parent->children.end(), [node](const std::unique_ptr<Node> &a) {\n                    return a.get() == node;\n                }));\n                /* Returning true means we removed node from parent */\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /* Removes ALL routes with the same handler as can be found with the given parameters.\n     * Removing a wildcard is done by removing ONE OF the methods the wildcard would match with.\n     * Example: If wildcard includes POST, GET, PUT, you can remove ALL THREE by removing GET. */\n    bool remove(std::string method, std::string pattern, uint32_t priority) {\n        uint32_t handler = findHandler(method, pattern, priority);\n        if (handler == UINT32_MAX) {\n            /* Not found or already removed, do nothing */\n            return false;\n        }\n\n        /* Cull the entire tree */\n        /* For all nodes in depth first tree traveral;\n         * if node contains handler - remove the handler -\n         * if node holds no handlers after removal, remove the node and return */\n        cullNode(nullptr, &root, handler);\n\n        /* Now remove the actual handler */\n        handlers.erase(handlers.begin() + (handler & HANDLER_MASK));\n\n        return true;\n    }\n};\n\n}\n\n#endif // UWS_HTTPROUTER_HPP\n"
  },
  {
    "path": "src/LocalCluster.h",
    "content": "/* This header is highly experimental and needs refactorings but will do for now */\n\n#include <thread>\n#include <algorithm>\n#include <mutex>\n\nunsigned int roundRobin = 0;\nunsigned int hardwareConcurrency = std::thread::hardware_concurrency();\nstd::vector<std::thread *> threads(hardwareConcurrency);\nstd::vector<uWS::SSLApp *> apps;\nstd::mutex m;\n\nnamespace uWS {\nstruct LocalCluster {\n\n    //std::vector<std::thread *> threads = std::thread::hardware_concurrency();\n    //std::vector<uWS::SSLApp *> apps;\n    //std::mutex m;\n\n\n    static void loadBalancer() {\n        static std::atomic<unsigned int> roundRobin = 0; // atomic fetch_add\n    }\n\n    LocalCluster(SocketContextOptions options = {}, std::function<void(uWS::SSLApp &)> cb = nullptr) {\n        std::transform(threads.begin(), threads.end(), threads.begin(), [options, &cb](std::thread *) {\n\n            return new std::thread([options, &cb]() {\n\n                // lock this\n                m.lock();\n                apps.emplace_back(new uWS::SSLApp(options));\n                uWS::SSLApp *app = apps.back();\n\n                cb(*app);\n                \n                app->preOpen([](struct us_socket_context_t *context, LIBUS_SOCKET_DESCRIPTOR fd) -> LIBUS_SOCKET_DESCRIPTOR {\n\n                    std::ignore = context;\n\n                    /* Distribute this socket in round robin fashion */\n                    //std::cout << \"About to load balance \" << fd << \" to \" << roundRobin << std::endl;\n\n                    auto receivingApp = apps[roundRobin];\n                    apps[roundRobin]->getLoop()->defer([fd, receivingApp]() {\n                        receivingApp->adoptSocket(fd);\n                    });\n\n                    roundRobin = (roundRobin + 1) % hardwareConcurrency;\n                    return (LIBUS_SOCKET_DESCRIPTOR) -1;\n                });\n                m.unlock();\n                app->run();\n                std::cout << \"Fallthrough!\" << std::endl;\n                delete app;\n            });\n        });\n\n        std::for_each(threads.begin(), threads.end(), [](std::thread *t) {\n            t->join();\n        });\n    }\n};\n}"
  },
  {
    "path": "src/Loop.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2020.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef UWS_LOOP_H\n#define UWS_LOOP_H\n\n/* The loop is lazily created per-thread and run with run() */\n\n#include \"LoopData.h\"\n#include <libusockets.h>\n#include <iostream>\n\nnamespace uWS {\n\n/* A prepared message is dependent on the Loop, so it belongs here */\nstruct PreparedMessage {\n    /* These should be a single alloation along with the PreparedMessage itself (they are static) */\n    std::string originalMessage, compressedMessage;\n    bool compressed;\n    int opCode;\n};\n\nstruct Loop {\nprivate:\n    static void wakeupCb(us_loop_t *loop) {\n        LoopData *loopData = (LoopData *) us_loop_ext(loop);\n\n        /* Swap current deferQueue */\n        loopData->deferMutex.lock();\n        int oldDeferQueue = loopData->currentDeferQueue;\n        loopData->currentDeferQueue = (loopData->currentDeferQueue + 1) % 2;\n        loopData->deferMutex.unlock();\n\n        /* Drain the queue */\n        for (auto &x : loopData->deferQueues[oldDeferQueue]) {\n            x();\n        }\n        loopData->deferQueues[oldDeferQueue].clear();\n    }\n\n    static void preCb(us_loop_t *loop) {\n        LoopData *loopData = (LoopData *) us_loop_ext(loop);\n\n        for (auto &p : loopData->preHandlers) {\n            p.second((Loop *) loop);\n        }\n    }\n\n    static void postCb(us_loop_t *loop) {\n        LoopData *loopData = (LoopData *) us_loop_ext(loop);\n\n        for (auto &p : loopData->postHandlers) {\n            p.second((Loop *) loop);\n        }\n\n        /* After every event loop iteration, we must not hold the cork buffer */\n        if (loopData->corkedSocket) {\n            std::cerr << \"Error: Cork buffer must not be held across event loop iterations!\" << std::endl;\n            std::terminate();\n        }\n    }\n\n    Loop() = delete;\n    ~Loop() = default;\n\n    Loop *init() {\n        new (us_loop_ext((us_loop_t *) this)) LoopData;\n        return this;\n    }\n\n    static Loop *create(void *hint) {\n        Loop *loop = ((Loop *) us_create_loop(hint, wakeupCb, preCb, postCb, sizeof(LoopData)))->init();\n\n        /* We also need some timers (should live off the one 4 second timer rather) */\n        LoopData *loopData = (LoopData *) us_loop_ext((struct us_loop_t *) loop);\n        loopData->dateTimer = us_create_timer((struct us_loop_t *) loop, 1, sizeof(LoopData *));\n        memcpy(us_timer_ext(loopData->dateTimer), &loopData, sizeof(LoopData *));\n        us_timer_set(loopData->dateTimer, [](struct us_timer_t *t) {\n            LoopData *loopData;\n            memcpy(&loopData, us_timer_ext(t), sizeof(LoopData *));\n            loopData->updateDate();\n        }, 1000, 1000);\n\n        return loop;\n    }\n\n    /* What to do with loops created with existingNativeLoop? */\n    struct LoopCleaner {\n        ~LoopCleaner() {\n            if(loop && cleanMe) {\n                loop->free();\n            }\n        }\n        Loop *loop = nullptr;\n        bool cleanMe = false;\n    };\n\n    static LoopCleaner &getLazyLoop() {\n        static thread_local LoopCleaner lazyLoop;\n        return lazyLoop;\n    }\n\npublic:\n\n    /* Preformatted messages need the Loop */\n    PreparedMessage prepareMessage(std::string_view message, int opCode, bool compress = true) {\n        /* The message could be formatted right here, but this optimization is not done yet */\n        PreparedMessage preparedMessage;\n        preparedMessage.compressed = compress;\n        preparedMessage.opCode = opCode;\n        preparedMessage.originalMessage = message;\n\n        LoopData *loopData = (LoopData *) us_loop_ext((us_loop_t *) this);\n\n        if (compress) {\n            /* Initialize loop's deflate inflate streams */\n            if (!loopData->zlibContext) {\n                loopData->zlibContext = new ZlibContext;\n                loopData->inflationStream = new InflationStream(CompressOptions::DEDICATED_DECOMPRESSOR);\n                loopData->deflationStream = new DeflationStream(CompressOptions::DEDICATED_COMPRESSOR);\n            }\n\n            preparedMessage.compressedMessage = loopData->deflationStream->deflate(loopData->zlibContext, {preparedMessage.originalMessage.data(), preparedMessage.originalMessage.length()}, true);\n        }\n\n        return preparedMessage;\n    }\n\n    /* Lazily initializes a per-thread loop and returns it.\n     * Will automatically free all initialized loops at exit. */\n    static Loop *get(void *existingNativeLoop = nullptr) {\n        if (!getLazyLoop().loop) {\n            /* If we are given a native loop pointer we pass that to uSockets and let it deal with it */\n            if (existingNativeLoop) {\n                /* Todo: here we want to pass the pointer, not a boolean */\n                getLazyLoop().loop = create(existingNativeLoop);\n                /* We cannot register automatic free here, must be manually done */\n            } else {\n                getLazyLoop().loop = create(nullptr);\n                getLazyLoop().cleanMe = true;\n            }\n        }\n\n        return getLazyLoop().loop;\n    }\n\n    /* Freeing the default loop should be done once */\n    void free() {\n        LoopData *loopData = (LoopData *) us_loop_ext((us_loop_t *) this);\n\n        /* Stop and free dateTimer first */\n        us_timer_close(loopData->dateTimer);\n\n        loopData->~LoopData();\n        /* uSockets will track whether this loop is owned by us or a borrowed alien loop */\n        us_loop_free((us_loop_t *) this);\n\n        /* Reset lazyLoop */\n        getLazyLoop().loop = nullptr;\n    }\n\n    void addPostHandler(void *key, MoveOnlyFunction<void(Loop *)> &&handler) {\n        LoopData *loopData = (LoopData *) us_loop_ext((us_loop_t *) this);\n\n        loopData->postHandlers.emplace(key, std::move(handler));\n    }\n\n    /* Bug: what if you remove a handler while iterating them? */\n    void removePostHandler(void *key) {\n        LoopData *loopData = (LoopData *) us_loop_ext((us_loop_t *) this);\n\n        loopData->postHandlers.erase(key);\n    }\n\n    void addPreHandler(void *key, MoveOnlyFunction<void(Loop *)> &&handler) {\n        LoopData *loopData = (LoopData *) us_loop_ext((us_loop_t *) this);\n\n        loopData->preHandlers.emplace(key, std::move(handler));\n    }\n\n    /* Bug: what if you remove a handler while iterating them? */\n    void removePreHandler(void *key) {\n        LoopData *loopData = (LoopData *) us_loop_ext((us_loop_t *) this);\n\n        loopData->preHandlers.erase(key);\n    }\n\n    /* Defer this callback on Loop's thread of execution */\n    void defer(MoveOnlyFunction<void()> &&cb) {\n        LoopData *loopData = (LoopData *) us_loop_ext((us_loop_t *) this);\n\n        //if (std::thread::get_id() == ) // todo: add fast path for same thread id\n        loopData->deferMutex.lock();\n        loopData->deferQueues[loopData->currentDeferQueue].emplace_back(std::move(cb));\n        loopData->deferMutex.unlock();\n\n        us_wakeup_loop((us_loop_t *) this);\n    }\n\n    /* Actively block and run this loop */\n    void run() {\n        us_loop_run((us_loop_t *) this);\n    }\n\n    /* Passively integrate with the underlying default loop */\n    /* Used to seamlessly integrate with third parties such as Node.js */\n    void integrate() {\n        us_loop_integrate((us_loop_t *) this);\n    }\n\n    /* Dynamically change this */\n    void setSilent(bool silent) {\n        ((LoopData *) us_loop_ext((us_loop_t *) this))->noMark = silent;\n    }\n};\n\n/* Can be called from any thread to run the thread local loop */\ninline void run() {\n    Loop::get()->run();\n}\n\n}\n\n#endif // UWS_LOOP_H\n"
  },
  {
    "path": "src/LoopData.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2020.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef UWS_LOOPDATA_H\n#define UWS_LOOPDATA_H\n\n#include <thread>\n#include <functional>\n#include <vector>\n#include <mutex>\n#include <map>\n#include <ctime>\n#include <cstdint>\n\n#include \"PerMessageDeflate.h\"\n#include \"MoveOnlyFunction.h\"\n\nstruct us_timer_t;\n\nnamespace uWS {\n\nstruct Loop;\n\nstruct alignas(16) LoopData {\n    friend struct Loop;\nprivate:\n    std::mutex deferMutex;\n    int currentDeferQueue = 0;\n    std::vector<MoveOnlyFunction<void()>> deferQueues[2];\n\n    /* Map from void ptr to handler */\n    std::map<void *, MoveOnlyFunction<void(Loop *)>> postHandlers, preHandlers;\n\npublic:\n    LoopData() {\n        updateDate();\n    }\n\n    ~LoopData() {\n        /* If we have had App.ws called with compression we need to clear this */\n        if (zlibContext) {\n            delete zlibContext;\n            delete inflationStream;\n            delete deflationStream;\n        }\n        delete [] corkBuffer;\n    }\n\n    void updateDate() {\n        cacheTimepoint = time(0);\n        struct tm tstruct = {};\n#ifdef _WIN32\n        /* Micro, fucking soft never follows spec. */\n        gmtime_s(&tstruct, &cacheTimepoint);\n#else\n        gmtime_r(&cacheTimepoint, &tstruct);\n#endif\n        static const char wday_name[][4] = {\n            \"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"\n        };\n        static const char mon_name[][4] = {\n            \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\",\n            \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"\n        };\n        snprintf(date, 32, \"%.3s, %.2u %.3s %.4u %.2u:%.2u:%.2u GMT\",\n            wday_name[tstruct.tm_wday],\n            tstruct.tm_mday % 99,\n            mon_name[tstruct.tm_mon],\n            (1900 + tstruct.tm_year) % 9999,\n            tstruct.tm_hour % 99,\n            tstruct.tm_min % 99,\n            tstruct.tm_sec % 99);\n    }\n\n    char date[32];\n    time_t cacheTimepoint = 0;\n\n    /* Be silent */\n    bool noMark = false;\n\n    /* Good 16k for SSL perf. */\n    static const unsigned int CORK_BUFFER_SIZE = 16 * 1024;\n\n    /* Cork data */\n    char *corkBuffer = new char[CORK_BUFFER_SIZE];\n    unsigned int corkOffset = 0;\n    void *corkedSocket = nullptr;\n\n    /* Per message deflate data */\n    ZlibContext *zlibContext = nullptr;\n    InflationStream *inflationStream = nullptr;\n    DeflationStream *deflationStream = nullptr;\n\n    us_timer_t *dateTimer;\n};\n\n}\n\n#endif // UWS_LOOPDATA_H\n"
  },
  {
    "path": "src/MessageParser.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2020.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/* Implements the common parser (RFC 822) used in both HTTP and Multipart parsing */\n\n#ifndef UWS_MESSAGE_PARSER_H\n#define UWS_MESSAGE_PARSER_H\n\n#include <string_view>\n#include <utility>\n#include <cstring>\n\n/* For now we have this one here */\n#define MAX_HEADERS 10\n\nnamespace uWS {\n\n    // should be templated on whether it needs at lest one header (http), or not (multipart)\n    static inline unsigned int getHeaders(char *postPaddedBuffer, char *end, std::pair<std::string_view, std::string_view> *headers) {\n        char *preliminaryKey, *preliminaryValue, *start = postPaddedBuffer;\n\n        for (unsigned int i = 0; i < MAX_HEADERS; i++) {\n            for (preliminaryKey = postPaddedBuffer; (*postPaddedBuffer != ':') & (*(unsigned char *)postPaddedBuffer > 32); *(postPaddedBuffer++) |= 32);\n            if (*postPaddedBuffer == '\\r') {\n                if ((postPaddedBuffer != end) & (postPaddedBuffer[1] == '\\n') /* & (i > 0) */) { // multipart does not require any headers like http does\n                    headers->first = std::string_view(nullptr, 0);\n                    return (unsigned int) ((postPaddedBuffer + 2) - start);\n                } else {\n                    return 0;\n                }\n            } else {\n                headers->first = std::string_view(preliminaryKey, (size_t) (postPaddedBuffer - preliminaryKey));\n                for (postPaddedBuffer++; (*postPaddedBuffer == ':' || *(unsigned char *)postPaddedBuffer < 33) && *postPaddedBuffer != '\\r'; postPaddedBuffer++);\n                preliminaryValue = postPaddedBuffer;\n                postPaddedBuffer = (char *) memchr(postPaddedBuffer, '\\r', end - postPaddedBuffer);\n                if (postPaddedBuffer && postPaddedBuffer[1] == '\\n') {\n                    headers->second = std::string_view(preliminaryValue, (size_t) (postPaddedBuffer - preliminaryValue));\n                    postPaddedBuffer += 2;\n                    headers++;\n                } else {\n                    return 0;\n                }\n            }\n        }\n        return 0;\n    }\n\n}\n\n#endif"
  },
  {
    "path": "src/MoveOnlyFunction.h",
    "content": "/*\nMIT License\n\nCopyright (c) 2020 Oleg Fatkhiev\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\n/* Sources fetched from https://github.com/ofats/any_invocable on 2021-02-19. */\n\n#ifndef _ANY_INVOKABLE_H_\n#define _ANY_INVOKABLE_H_\n\n#include <functional>\n\n#if !defined(__cpp_lib_move_only_function) || __cpp_lib_move_only_function < 202110L\n\n#include <memory>\n#include <type_traits>\n\n// clang-format off\n/*\nnamespace std {\n  template<class Sig> class any_invocable; // never defined\n\n  template<class R, class... ArgTypes>\n  class any_invocable<R(ArgTypes...) cv ref noexcept(noex)> {\n  public:\n    using result_type = R;\n\n    // SECTION.3, construct/copy/destroy\n    any_invocable() noexcept;\n    any_invocable(nullptr_t) noexcept;\n    any_invocable(any_invocable&&) noexcept;\n    template<class F> any_invocable(F&&);\n\n    template<class T, class... Args>\n      explicit any_invocable(in_place_type_t<T>, Args&&...);\n    template<class T, class U, class... Args>\n      explicit any_invocable(in_place_type_t<T>, initializer_list<U>, Args&&...);\n\n    any_invocable& operator=(any_invocable&&) noexcept;\n    any_invocable& operator=(nullptr_t) noexcept;\n    template<class F> any_invocable& operator=(F&&);\n    template<class F> any_invocable& operator=(reference_wrapper<F>) noexcept;\n\n    ~any_invocable();\n\n    // SECTION.4, any_invocable modifiers\n    void swap(any_invocable&) noexcept;\n\n    // SECTION.5, any_invocable capacity\n    explicit operator bool() const noexcept;\n\n    // SECTION.6, any_invocable invocation\n    R operator()(ArgTypes...) cv ref noexcept(noex);\n\n    // SECTION.7, null pointer comparisons\n    friend bool operator==(const any_invocable&, nullptr_t) noexcept;\n\n    // SECTION.8, specialized algorithms\n    friend void swap(any_invocable&, any_invocable&) noexcept;\n  };\n}\n*/\n// clang-format on\n\nnamespace ofats {\n\nnamespace any_detail {\n\nusing buffer = std::aligned_storage_t<sizeof(void*) * 2, alignof(void*)>;\n\ntemplate <class T>\ninline constexpr bool is_small_object_v =\n    sizeof(T) <= sizeof(buffer) && alignof(buffer) % alignof(T) == 0 &&\n    std::is_nothrow_move_constructible_v<T>;\n\nunion storage {\n  void* ptr_ = nullptr;\n  buffer buf_;\n};\n\nenum class action { destroy, move };\n\ntemplate <class R, class... ArgTypes>\nstruct handler_traits {\n  template <class Derived>\n  struct handler_base {\n    static void handle(action act, storage* current, storage* other = nullptr) {\n      switch (act) {\n        case (action::destroy):\n          Derived::destroy(*current);\n          break;\n        case (action::move):\n          Derived::move(*current, *other);\n          break;\n      }\n    }\n  };\n\n  template <class T>\n  struct small_handler : handler_base<small_handler<T>> {\n    template <class... Args>\n    static void create(storage& s, Args&&... args) {\n      new (static_cast<void*>(&s.buf_)) T(std::forward<Args>(args)...);\n    }\n\n    static void destroy(storage& s) noexcept {\n      T& value = *static_cast<T*>(static_cast<void*>(&s.buf_));\n      value.~T();\n    }\n\n    static void move(storage& dst, storage& src) noexcept {\n      create(dst, std::move(*static_cast<T*>(static_cast<void*>(&src.buf_))));\n      destroy(src);\n    }\n\n    static R call(storage& s, ArgTypes... args) {\n      return std::invoke(*static_cast<T*>(static_cast<void*>(&s.buf_)),\n                         std::forward<ArgTypes>(args)...);\n    }\n  };\n\n  template <class T>\n  struct large_handler : handler_base<large_handler<T>> {\n    template <class... Args>\n    static void create(storage& s, Args&&... args) {\n      s.ptr_ = new T(std::forward<Args>(args)...);\n    }\n\n    static void destroy(storage& s) noexcept { delete static_cast<T*>(s.ptr_); }\n\n    static void move(storage& dst, storage& src) noexcept {\n      dst.ptr_ = src.ptr_;\n    }\n\n    static R call(storage& s, ArgTypes... args) {\n      return std::invoke(*static_cast<T*>(s.ptr_),\n                         std::forward<ArgTypes>(args)...);\n    }\n  };\n\n  template <class T>\n  using handler = std::conditional_t<is_small_object_v<T>, small_handler<T>,\n                                     large_handler<T>>;\n};\n\ntemplate <class T>\nstruct is_in_place_type : std::false_type {};\n\ntemplate <class T>\nstruct is_in_place_type<std::in_place_type_t<T>> : std::true_type {};\n\ntemplate <class T>\ninline constexpr auto is_in_place_type_v = is_in_place_type<T>::value;\n\ntemplate <class R, bool is_noexcept, class... ArgTypes>\nclass any_invocable_impl {\n  template <class T>\n  using handler =\n      typename any_detail::handler_traits<R, ArgTypes...>::template handler<T>;\n\n  using storage = any_detail::storage;\n  using action = any_detail::action;\n  using handle_func = void (*)(any_detail::action, any_detail::storage*,\n                               any_detail::storage*);\n  using call_func = R (*)(any_detail::storage&, ArgTypes...);\n\n public:\n  using result_type = R;\n\n  any_invocable_impl() noexcept = default;\n  any_invocable_impl(std::nullptr_t) noexcept {}\n  any_invocable_impl(any_invocable_impl&& rhs) noexcept {\n    if (rhs.handle_) {\n      handle_ = rhs.handle_;\n      handle_(action::move, &storage_, &rhs.storage_);\n      call_ = rhs.call_;\n      rhs.handle_ = nullptr;\n    }\n  }\n\n  any_invocable_impl& operator=(any_invocable_impl&& rhs) noexcept {\n    any_invocable_impl{std::move(rhs)}.swap(*this);\n    return *this;\n  }\n  any_invocable_impl& operator=(std::nullptr_t) noexcept {\n    destroy();\n    return *this;\n  }\n\n  ~any_invocable_impl() { destroy(); }\n\n  void swap(any_invocable_impl& rhs) noexcept {\n    if (handle_) {\n      if (rhs.handle_) {\n        storage tmp;\n        handle_(action::move, &tmp, &storage_);\n        rhs.handle_(action::move, &storage_, &rhs.storage_);\n        handle_(action::move, &rhs.storage_, &tmp);\n        std::swap(handle_, rhs.handle_);\n        std::swap(call_, rhs.call_);\n      } else {\n        rhs.swap(*this);\n      }\n    } else if (rhs.handle_) {\n      rhs.handle_(action::move, &storage_, &rhs.storage_);\n      handle_ = rhs.handle_;\n      call_ = rhs.call_;\n      rhs.handle_ = nullptr;\n    }\n  }\n\n  explicit operator bool() const noexcept { return handle_ != nullptr; }\n\n protected:\n  template <class F, class... Args>\n  void create(Args&&... args) {\n    using hdl = handler<F>;\n    hdl::create(storage_, std::forward<Args>(args)...);\n    handle_ = &hdl::handle;\n    call_ = &hdl::call;\n  }\n\n  void destroy() noexcept {\n    if (handle_) {\n      handle_(action::destroy, &storage_, nullptr);\n      handle_ = nullptr;\n    }\n  }\n\n  R call(ArgTypes... args) noexcept(is_noexcept) {\n    return call_(storage_, std::forward<ArgTypes>(args)...);\n  }\n\n  friend bool operator==(const any_invocable_impl& f, std::nullptr_t) noexcept {\n    return !f;\n  }\n  friend bool operator==(std::nullptr_t, const any_invocable_impl& f) noexcept {\n    return !f;\n  }\n  friend bool operator!=(const any_invocable_impl& f, std::nullptr_t) noexcept {\n    return static_cast<bool>(f);\n  }\n  friend bool operator!=(std::nullptr_t, const any_invocable_impl& f) noexcept {\n    return static_cast<bool>(f);\n  }\n\n  friend void swap(any_invocable_impl& lhs, any_invocable_impl& rhs) noexcept {\n    lhs.swap(rhs);\n  }\n\n private:\n  storage storage_;\n  handle_func handle_ = nullptr;\n  call_func call_;\n};\n\ntemplate <class T>\nusing remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;\n\ntemplate <class AI, class F, bool noex, class R, class FCall, class... ArgTypes>\nusing can_convert = std::conjunction<\n    std::negation<std::is_same<remove_cvref_t<F>, AI>>,\n    std::negation<any_detail::is_in_place_type<remove_cvref_t<F>>>,\n    std::is_invocable_r<R, FCall, ArgTypes...>,\n    std::bool_constant<(!noex ||\n                        std::is_nothrow_invocable_r_v<R, FCall, ArgTypes...>)>,\n    std::is_constructible<std::decay_t<F>, F>>;\n\n}  // namespace any_detail\n\ntemplate <class Signature>\nclass any_invocable;\n\n#define __OFATS_ANY_INVOCABLE(cv, ref, noex, inv_quals)                        \\\n  template <class R, class... ArgTypes>                                        \\\n  class any_invocable<R(ArgTypes...) cv ref noexcept(noex)>                    \\\n      : public any_detail::any_invocable_impl<R, noex, ArgTypes...> {          \\\n    using base_type = any_detail::any_invocable_impl<R, noex, ArgTypes...>;    \\\n                                                                               \\\n   public:                                                                     \\\n    using base_type::base_type;                                                \\\n                                                                               \\\n    template <                                                                 \\\n        class F,                                                               \\\n        class = std::enable_if_t<any_detail::can_convert<                      \\\n            any_invocable, F, noex, R, F inv_quals, ArgTypes...>::value>>      \\\n    any_invocable(F&& f) {                                                     \\\n      base_type::template create<std::decay_t<F>>(std::forward<F>(f));         \\\n    }                                                                          \\\n                                                                               \\\n    template <class T, class... Args, class VT = std::decay_t<T>,              \\\n              class = std::enable_if_t<                                        \\\n                  std::is_move_constructible_v<VT> &&                          \\\n                  std::is_constructible_v<VT, Args...> &&                      \\\n                  std::is_invocable_r_v<R, VT inv_quals, ArgTypes...> &&       \\\n                  (!noex || std::is_nothrow_invocable_r_v<R, VT inv_quals,     \\\n                                                          ArgTypes...>)>>      \\\n    explicit any_invocable(std::in_place_type_t<T>, Args&&... args) {          \\\n      base_type::template create<VT>(std::forward<Args>(args)...);             \\\n    }                                                                          \\\n                                                                               \\\n    template <                                                                 \\\n        class T, class U, class... Args, class VT = std::decay_t<T>,           \\\n        class = std::enable_if_t<                                              \\\n            std::is_move_constructible_v<VT> &&                                \\\n            std::is_constructible_v<VT, std::initializer_list<U>&, Args...> && \\\n            std::is_invocable_r_v<R, VT inv_quals, ArgTypes...> &&             \\\n            (!noex ||                                                          \\\n             std::is_nothrow_invocable_r_v<R, VT inv_quals, ArgTypes...>)>>    \\\n    explicit any_invocable(std::in_place_type_t<T>,                            \\\n                           std::initializer_list<U> il, Args&&... args) {      \\\n      base_type::template create<VT>(il, std::forward<Args>(args)...);         \\\n    }                                                                          \\\n                                                                               \\\n    template <class F, class FDec = std::decay_t<F>>                           \\\n    std::enable_if_t<!std::is_same_v<FDec, any_invocable> &&                   \\\n                         std::is_move_constructible_v<FDec>,                   \\\n                     any_invocable&>                                           \\\n    operator=(F&& f) {                                                         \\\n      any_invocable{std::forward<F>(f)}.swap(*this);                           \\\n      return *this;                                                            \\\n    }                                                                          \\\n    template <class F>                                                         \\\n    any_invocable& operator=(std::reference_wrapper<F> f) {                    \\\n      any_invocable{f}.swap(*this);                                            \\\n      return *this;                                                            \\\n    }                                                                          \\\n                                                                               \\\n    R operator()(ArgTypes... args) cv ref noexcept(noex) {                     \\\n      return base_type::call(std::forward<ArgTypes>(args)...);                 \\\n    }                                                                          \\\n  };\n\n// cv -> {`empty`, const}\n// ref -> {`empty`, &, &&}\n// noex -> {true, false}\n// inv_quals -> (is_empty(ref) ? & : ref)\n__OFATS_ANY_INVOCABLE(, , false, &)               // 000\n__OFATS_ANY_INVOCABLE(, , true, &)                // 001\n__OFATS_ANY_INVOCABLE(, &, false, &)              // 010\n__OFATS_ANY_INVOCABLE(, &, true, &)               // 011\n__OFATS_ANY_INVOCABLE(, &&, false, &&)            // 020\n__OFATS_ANY_INVOCABLE(, &&, true, &&)             // 021\n__OFATS_ANY_INVOCABLE(const, , false, const&)     // 100\n__OFATS_ANY_INVOCABLE(const, , true, const&)      // 101\n__OFATS_ANY_INVOCABLE(const, &, false, const&)    // 110\n__OFATS_ANY_INVOCABLE(const, &, true, const&)     // 111\n__OFATS_ANY_INVOCABLE(const, &&, false, const&&)  // 120\n__OFATS_ANY_INVOCABLE(const, &&, true, const&&)   // 121\n\n#undef __OFATS_ANY_INVOCABLE\n\n}  // namespace ofats\n\n/* We, uWebSockets define our own type */\nnamespace uWS {\n  template <class T>\n  using MoveOnlyFunction = ofats::any_invocable<T>;\n}\n\n#else // !defined(__cpp_lib_move_only_function) || __cpp_lib_move_only_function < 202110L\n\nnamespace uWS {\n  template <class T>\n  using MoveOnlyFunction = std::move_only_function<T>;\n}\n\n#endif\n\n#endif  // _ANY_INVOKABLE_H_\n"
  },
  {
    "path": "src/Multipart.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2020.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/* Implements the multipart protocol. Builds atop parts of our common http parser (not yet refactored that way). */\n/* https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html */\n\n#ifndef UWS_MULTIPART_H\n#define UWS_MULTIPART_H\n\n#include \"MessageParser.h\"\n\n#include <string_view>\n#include <optional>\n#include <cstring>\n#include <utility>\n#include <cctype>\n\nnamespace uWS {\n\n    /* This one could possibly be shared with ExtensionsParser to some degree */\n    struct ParameterParser {\n\n        /* Takes the line, commonly given as content-disposition header in the multipart */\n        ParameterParser(std::string_view line) {\n            remainingLine = line;\n        }\n\n        /* Returns next key/value where value can simply be empty.\n         * If key (first) is empty then we are at the end */\n        std::pair<std::string_view, std::string_view> getKeyValue() {\n            auto key = getToken();\n            auto op = getToken();\n\n            if (!op.length()) {\n                return {key, \"\"};\n            }\n\n            if (op[0] != ';') {\n                auto value = getToken();\n                /* Strip ; or if at end, nothing */\n                getToken();\n                return {key, value};\n            }\n\n            return {key, \"\"};\n        }\n\n    private:\n        std::string_view remainingLine;\n\n        /* Consumes a token from the line. Will \"unquote\" strings */\n        std::string_view getToken() {\n            /* Strip whitespace */\n            while (remainingLine.length() && isspace(remainingLine[0])) {\n                remainingLine.remove_prefix(1);\n            }\n\n            if (!remainingLine.length()) {\n                /* All we had was space */\n                return {};\n            } else {\n                /* Are we at an operator? */\n                if (remainingLine[0] == ';' || remainingLine[0] == '=') {\n                    auto op = remainingLine.substr(0, 1);\n                    remainingLine.remove_prefix(1);\n                    return op;\n                } else {\n                    /* Are we at a quoted string? */\n                    if (remainingLine[0] == '\\\"') {\n                        /* Remove first quote and start counting */\n                        remainingLine.remove_prefix(1);\n                        auto quote = remainingLine;\n                        int quoteLength = 0;\n\n                        /* Read anything until other double quote appears */\n                        while (remainingLine.length() && remainingLine[0] != '\\\"') {\n                            remainingLine.remove_prefix(1);\n                            quoteLength++;\n                        }\n\n                        /* We can't remove_prefix if we have nothing to remove */\n                        if (!remainingLine.length()) {\n                            return {};\n                        }\n\n                        remainingLine.remove_prefix(1);\n                        return quote.substr(0, quoteLength);\n                    } else {\n                        /* Read anything until ; = space or end */\n                        std::string_view token = remainingLine;\n\n                        int tokenLength = 0;\n                        while (remainingLine.length() && remainingLine[0] != ';' && remainingLine[0] != '=' && !isspace(remainingLine[0])) {\n                            remainingLine.remove_prefix(1);\n                            tokenLength++;\n                        }\n\n                        return token.substr(0, tokenLength);\n                    }\n                }\n            }\n\n            /* Nothing */\n            return \"\";\n        }\n    };\n\n    struct MultipartParser {\n\n        /* 2 chars of hyphen + 1 - 70 chars of boundary */\n        char prependedBoundaryBuffer[72];\n        std::string_view prependedBoundary;\n        std::string_view remainingBody;\n        bool first = true;\n\n        /* I think it is more than sane to limit this to 10 per part */\n        //static const int MAX_HEADERS = 10;\n\n        /* Construct the parser based on contentType (reads boundary) */\n        MultipartParser(std::string_view contentType) {\n\n            /* We expect the form \"multipart/something;somethingboundary=something\" */\n            if (contentType.length() < 10 || contentType.substr(0, 10) != \"multipart/\") {\n                return;\n            }\n\n            /* For now we simply guess boundary will lie between = and end. This is not entirely\n            * standards compliant as boundary may be expressed with or without \" and spaces */\n            auto equalToken = contentType.find('=', 10);\n            if (equalToken != std::string_view::npos) {\n\n                /* Boundary must be less than or equal to 70 chars yet 1 char or longer */\n                std::string_view boundary = contentType.substr(equalToken + 1);\n                if (!boundary.length() || boundary.length() > 70) {\n                    /* Invalid size */\n                    return;\n                }\n\n                /* Prepend it with two hyphens */\n                prependedBoundaryBuffer[0] = prependedBoundaryBuffer[1] = '-';\n                memcpy(&prependedBoundaryBuffer[2], boundary.data(), boundary.length());\n\n                prependedBoundary = {prependedBoundaryBuffer, boundary.length() + 2};\n            }\n        }\n\n        /* Is this even a valid multipart request? */\n        bool isValid() {\n            return prependedBoundary.length() != 0;\n        }\n\n        /* Set the body once, before getting any parts */\n        void setBody(std::string_view body) {\n            remainingBody = body;\n        }\n\n        /* Parse out the next part's data, filling the headers. Returns nullopt on end or error. */\n        std::optional<std::string_view> getNextPart(std::pair<std::string_view, std::string_view> *headers) {\n\n            /* The remaining two hyphens should be shorter than the boundary */\n            if (remainingBody.length() < prependedBoundary.length()) {\n                /* We are done now */\n                return std::nullopt;\n            }\n\n            if (first) {\n                auto nextBoundary = remainingBody.find(prependedBoundary);\n                if (nextBoundary == std::string_view::npos) {\n                    /* Cannot parse */\n                    return std::nullopt;\n                }\n\n                /* Toss away boundary and anything before it */\n                remainingBody.remove_prefix(nextBoundary + prependedBoundary.length());\n                first = false;\n            }\n\n            auto nextEndBoundary = remainingBody.find(prependedBoundary);\n            if (nextEndBoundary == std::string_view::npos) {\n                /* Cannot parse (or simply done) */\n                return std::nullopt;\n            }\n\n            std::string_view part = remainingBody.substr(0, nextEndBoundary);\n            remainingBody.remove_prefix(nextEndBoundary + prependedBoundary.length());\n\n            /* Also strip rn before and rn after the part */\n            if (part.length() < 4) {\n                /* Cannot strip */\n                return std::nullopt;\n            }\n            part.remove_prefix(2);\n            part.remove_suffix(2);\n\n            /* We are allowed to post pad like this because we know the boundary is at least 2 bytes */\n            /* This makes parsing a second pass invalid, so you can only iterate over parts once */\n            memset((char *) part.data() + part.length(), '\\r', 1);\n\n            /* For this to be a valid part, we need to consume at least 4 bytes (\\r\\n\\r\\n) */\n            int consumed = getHeaders((char *) part.data(), (char *) part.data() + part.length(), headers);\n\n            if (!consumed) {\n                /* This is an invalid part */\n                return std::nullopt;\n            }\n\n            /* Strip away the headers from the part body data */\n            part.remove_prefix(consumed);\n\n            /* Now pass whatever is remaining of the part */\n            return part;\n        }\n    };\n\n}\n\n#endif\n"
  },
  {
    "path": "src/PerMessageDeflate.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2021.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/* This standalone module implements deflate / inflate streams */\n\n#ifndef UWS_PERMESSAGEDEFLATE_H\n#define UWS_PERMESSAGEDEFLATE_H\n\n#include <cstdint>\n#include <cstring>\n\n/* We always define these options no matter if ZLIB is enabled or not */\nnamespace uWS {\n    /* Compressor mode is 8 lowest bits where HIGH4(windowBits), LOW4(memLevel).\n     * Decompressor mode is 8 highest bits LOW4(windowBits).\n     * If compressor or decompressor bits are 1, then they are shared.\n     * If everything is just simply 0, then everything is disabled. */\n    enum CompressOptions : uint16_t {\n        /* These are not actual compression options */\n        _COMPRESSOR_MASK = 0x00FF,\n        _DECOMPRESSOR_MASK = 0x0F00,\n        /* Disabled, shared, shared are \"special\" values */\n        DISABLED = 0,\n        SHARED_COMPRESSOR = 1,\n        SHARED_DECOMPRESSOR = 1 << 8,\n        /* Highest 4 bits describe decompressor */\n        DEDICATED_DECOMPRESSOR_32KB = 15 << 8,\n        DEDICATED_DECOMPRESSOR_16KB = 14 << 8,\n        DEDICATED_DECOMPRESSOR_8KB = 13 << 8,\n        DEDICATED_DECOMPRESSOR_4KB = 12 << 8,\n        DEDICATED_DECOMPRESSOR_2KB = 11 << 8,\n        DEDICATED_DECOMPRESSOR_1KB = 10 << 8,\n        DEDICATED_DECOMPRESSOR_512B = 9 << 8,\n        /* Same as 32kb */\n        DEDICATED_DECOMPRESSOR = 15 << 8,\n\n        /* Lowest 8 bit describe compressor */\n        DEDICATED_COMPRESSOR_3KB = 9 << 4 | 1,\n        DEDICATED_COMPRESSOR_4KB = 9 << 4 | 2,\n        DEDICATED_COMPRESSOR_8KB = 10 << 4 | 3,\n        DEDICATED_COMPRESSOR_16KB = 11 << 4 | 4,\n        DEDICATED_COMPRESSOR_32KB = 12 << 4 | 5,\n        DEDICATED_COMPRESSOR_64KB = 13 << 4 | 6,\n        DEDICATED_COMPRESSOR_128KB = 14 << 4 | 7,\n        DEDICATED_COMPRESSOR_256KB = 15 << 4 | 8,\n        /* Same as 256kb */\n        DEDICATED_COMPRESSOR = 15 << 4 | 8\n    };\n}\n\n#if !defined(UWS_NO_ZLIB) && !defined(UWS_MOCK_ZLIB)\n#include <zlib.h>\n#endif\n\n#include <string>\n#include <optional>\n\n#ifdef UWS_USE_LIBDEFLATE\n#include \"libdeflate.h\"\n#include <cstring>\n#endif\n\nnamespace uWS {\n\n/* Do not compile this module if we don't want it */\n#if defined(UWS_NO_ZLIB) || defined(UWS_MOCK_ZLIB)\nstruct ZlibContext {};\nstruct InflationStream {\n    std::optional<std::string_view> inflate(ZlibContext * /*zlibContext*/, std::string_view compressed, size_t maxPayloadLength, bool /*reset*/) {\n        return compressed.substr(0, std::min(maxPayloadLength, compressed.length()));\n    }\n    InflationStream(CompressOptions /*compressOptions*/) {\n    }\n};\nstruct DeflationStream {\n    std::string_view deflate(ZlibContext * /*zlibContext*/, std::string_view raw, bool /*reset*/) {\n        return raw;\n    }\n    DeflationStream(CompressOptions /*compressOptions*/) {\n    }\n};\n#else\n\n#define LARGE_BUFFER_SIZE 1024 * 16 // todo: fix this\n\nstruct ZlibContext {\n    /* Any returned data is valid until next same-class call.\n     * We need to have two classes to allow inflation followed\n     * by many deflations without modifying the inflation */\n    std::string dynamicDeflationBuffer;\n    std::string dynamicInflationBuffer;\n    char *deflationBuffer;\n    char *inflationBuffer;\n\n#ifdef UWS_USE_LIBDEFLATE\n    libdeflate_decompressor *decompressor;\n    libdeflate_compressor *compressor;\n#endif\n\n    ZlibContext() {\n        deflationBuffer = (char *) malloc(LARGE_BUFFER_SIZE);\n        inflationBuffer = (char *) malloc(LARGE_BUFFER_SIZE);\n\n#ifdef UWS_USE_LIBDEFLATE\n        decompressor = libdeflate_alloc_decompressor();\n        compressor = libdeflate_alloc_compressor(6);\n#endif\n    }\n\n    ~ZlibContext() {\n        free(deflationBuffer);\n        free(inflationBuffer);\n\n#ifdef UWS_USE_LIBDEFLATE\n        libdeflate_free_decompressor(decompressor);\n        libdeflate_free_compressor(compressor);\n#endif\n    }\n};\n\nstruct DeflationStream {\n    z_stream deflationStream = {};\n\n    DeflationStream(CompressOptions compressOptions) {\n\n        /* Sliding inflator should be about 44kb by default, less than compressor */\n\n        /* Memory usage is given by 2 ^ (windowBits + 2) + 2 ^ (memLevel + 9) */\n        int windowBits = -(int) ((compressOptions & _COMPRESSOR_MASK) >> 4), memLevel = compressOptions & 0xF;\n\n        //printf(\"windowBits: %d, memLevel: %d\\n\", windowBits, memLevel);\n\n        deflateInit2(&deflationStream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, windowBits, memLevel, Z_DEFAULT_STRATEGY);\n    }\n\n    /* Deflate and optionally reset. You must not deflate an empty string. */\n    std::string_view deflate(ZlibContext *zlibContext, std::string_view raw, bool reset) {\n\n        /* Odd place to clear this one, fix */\n        zlibContext->dynamicDeflationBuffer.clear();\n\n        deflationStream.next_in = (Bytef *) raw.data();\n        deflationStream.avail_in = (unsigned int) raw.length();\n\n        /* This buffer size has to be at least 6 bytes for Z_SYNC_FLUSH to work */\n        const int DEFLATE_OUTPUT_CHUNK = LARGE_BUFFER_SIZE;\n\n        int err;\n        do {\n            deflationStream.next_out = (Bytef *) zlibContext->deflationBuffer;\n            deflationStream.avail_out = DEFLATE_OUTPUT_CHUNK;\n\n            err = ::deflate(&deflationStream, Z_SYNC_FLUSH);\n            if (Z_OK == err && deflationStream.avail_out == 0) {\n                zlibContext->dynamicDeflationBuffer.append(zlibContext->deflationBuffer, DEFLATE_OUTPUT_CHUNK - deflationStream.avail_out);\n                continue;\n            } else {\n                break;\n            }\n        } while (true);\n\n        /* This must not change avail_out */\n        if (reset) {\n            deflateReset(&deflationStream);\n        }\n\n        if (zlibContext->dynamicDeflationBuffer.length()) {\n            zlibContext->dynamicDeflationBuffer.append(zlibContext->deflationBuffer, DEFLATE_OUTPUT_CHUNK - deflationStream.avail_out);\n\n            return std::string_view((char *) zlibContext->dynamicDeflationBuffer.data(), zlibContext->dynamicDeflationBuffer.length() - 4);\n        }\n\n        /* Note: We will get an interger overflow resulting in heap buffer overflow if Z_BUF_ERROR is returned\n         * from passing 0 as avail_in. Therefore we must not deflate an empty string */\n        return {\n            zlibContext->deflationBuffer,\n            DEFLATE_OUTPUT_CHUNK - deflationStream.avail_out - 4\n        };\n    }\n\n    ~DeflationStream() {\n        deflateEnd(&deflationStream);\n    }\n};\n\nstruct InflationStream {\n    z_stream inflationStream = {};\n\n    InflationStream(CompressOptions compressOptions) {\n        /* Inflation windowBits are the top 8 bits of the 16 bit compressOptions */\n        inflateInit2(&inflationStream, -(compressOptions >> 8));\n    }\n\n    ~InflationStream() {\n        inflateEnd(&inflationStream);\n    }\n\n    /* Zero length inflates are possible and valid */\n    std::optional<std::string_view> inflate(ZlibContext *zlibContext, std::string_view compressed, size_t maxPayloadLength, bool reset) {\n\n#ifdef UWS_USE_LIBDEFLATE\n        if (reset) {\n            /* Try fast path first (assuming single DEFLATE block and shared compressor aka reset = true) */\n            size_t written = 0, consumed;\n            zlibContext->dynamicInflationBuffer.clear();\n            zlibContext->dynamicInflationBuffer.reserve(maxPayloadLength);\n\n            ((char *)compressed.data())[0] |= 0x1; // BFINAL = 1\n            libdeflate_result res = libdeflate_deflate_decompress_ex(zlibContext->decompressor, compressed.data(), compressed.length(), zlibContext->dynamicInflationBuffer.data(), maxPayloadLength, &consumed, &written);\n    \n            /* Still not entirely sure why 1 extra zero byte is optional and ignored by both zlib and libdeflate in some cases */\n            /* Minimal reproducer is load_test.c with 102 byte message size. It should be tested with Chrome at various message sizes as well. */\n            if (res == 0 && (consumed == compressed.length() || (consumed + 1 == compressed.length() && compressed[consumed] == '\\0'))) {\n                return std::string_view(zlibContext->dynamicInflationBuffer.data(), written);\n            } else {\n                /* We can only end up here if the first DEFLATE block was not the last, so mark it as such */\n                ((char *)compressed.data())[0] &= ~0x1; // BFINAL = 0\n            }\n        }\n#endif\n\n        /* Save off the bytes we're about to overwrite */\n        char* tailLocation = (char*)compressed.data() + compressed.length();\n        char preTailBytes[4];\n        memcpy(preTailBytes, tailLocation, 4);\n\n        /* Append tail to chunk */\n        unsigned char tail[4] = {0x00, 0x00, 0xff, 0xff};\n        memcpy(tailLocation, tail, 4);\n        compressed = {compressed.data(), compressed.length() + 4};\n\n        /* We clear this one here, could be done better */\n        zlibContext->dynamicInflationBuffer.clear();\n\n        inflationStream.next_in = (Bytef *) compressed.data();\n        inflationStream.avail_in = (unsigned int) compressed.length();\n\n        int err;\n        do {\n            inflationStream.next_out = (Bytef *) zlibContext->inflationBuffer;\n            inflationStream.avail_out = LARGE_BUFFER_SIZE;\n\n            err = ::inflate(&inflationStream, Z_SYNC_FLUSH);\n            if (err == Z_OK && inflationStream.avail_out) {\n                break;\n            }\n\n            zlibContext->dynamicInflationBuffer.append(zlibContext->inflationBuffer, LARGE_BUFFER_SIZE - inflationStream.avail_out);\n\n\n        } while (inflationStream.avail_out == 0 && zlibContext->dynamicInflationBuffer.length() <= maxPayloadLength);\n\n        if (reset) {\n            inflateReset(&inflationStream);\n        }\n\n        /* Restore the bytes we used for the tail */\n        memcpy(tailLocation, preTailBytes, 4);\n\n        if ((err != Z_BUF_ERROR && err != Z_OK) || zlibContext->dynamicInflationBuffer.length() > maxPayloadLength) {\n            return std::nullopt;\n        }\n\n        if (zlibContext->dynamicInflationBuffer.length()) {\n            zlibContext->dynamicInflationBuffer.append(zlibContext->inflationBuffer, LARGE_BUFFER_SIZE - inflationStream.avail_out);\n\n            /* Let's be strict about the max size */\n            if (zlibContext->dynamicInflationBuffer.length() > maxPayloadLength) {\n                return std::nullopt;\n            }\n\n            return std::string_view(zlibContext->dynamicInflationBuffer.data(), zlibContext->dynamicInflationBuffer.length());\n        }\n\n        /* Let's be strict about the max size */\n        if ((LARGE_BUFFER_SIZE - inflationStream.avail_out) > maxPayloadLength) {\n            return std::nullopt;\n        }\n\n        return std::string_view(zlibContext->inflationBuffer, LARGE_BUFFER_SIZE - inflationStream.avail_out);\n    }\n\n};\n\n#endif\n\n}\n\n#endif // UWS_PERMESSAGEDEFLATE_H\n"
  },
  {
    "path": "src/ProxyParser.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2020.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/* This module implements The PROXY Protocol v2 */\n\n#ifndef UWS_PROXY_PARSER_H\n#define UWS_PROXY_PARSER_H\n\n#ifdef UWS_WITH_PROXY\n\nnamespace uWS {\n\nstruct proxy_hdr_v2 {\n    uint8_t sig[12];  /* hex 0D 0A 0D 0A 00 0D 0A 51 55 49 54 0A */\n    uint8_t ver_cmd;  /* protocol version and command */\n    uint8_t fam;      /* protocol family and address */\n    uint16_t len;     /* number of following bytes part of the header */\n};\n\nunion proxy_addr {\n    struct {        /* for TCP/UDP over IPv4, len = 12 */\n        uint32_t src_addr;\n        uint32_t dst_addr;\n        uint16_t src_port;\n        uint16_t dst_port;\n    } ipv4_addr;\n    struct {        /* for TCP/UDP over IPv6, len = 36 */\n            uint8_t  src_addr[16];\n            uint8_t  dst_addr[16];\n            uint16_t src_port;\n            uint16_t dst_port;\n    } ipv6_addr;\n};\n\n/* Byte swap for little-endian systems */\n/* Todo: This functions should be shared with the one in WebSocketProtocol.h! */\ntemplate <typename T>\nT _cond_byte_swap(T value) {\n    uint32_t endian_test = 1;\n    if (*((char *)&endian_test)) {\n        union {\n            T i;\n            uint8_t b[sizeof(T)];\n        } src = { value }, dst;\n\n        for (unsigned int i = 0; i < sizeof(value); i++) {\n            dst.b[i] = src.b[sizeof(value) - 1 - i];\n        }\n\n        return dst.i;\n    }\n    return value;\n}\n\nstruct ProxyParser {\nprivate:\n    union proxy_addr addr;\n\n    /* Default family of 0 signals no proxy address */\n    uint8_t family = 0;\n\npublic:\n    /* Returns 4 or 16 bytes source address */\n    std::string_view getSourceAddress() {\n\n        // UNSPEC family and protocol\n        if (family == 0) {\n            return {};\n        }\n\n        if ((family & 0xf0) >> 4 == 1) {\n            /* Family 1 is INET4 */\n            return {(char *) &addr.ipv4_addr.src_addr, 4};\n        } else {\n            /* Family 2 is INET6 */\n            return {(char *) &addr.ipv6_addr.src_addr, 16};\n        }\n    }\n\n    unsigned int getSourcePort() {\n\n        // UNSPEC family and protocol\n        if (family == 0) {\n            return {};\n        }\n\n        if ((family & 0xf0) >> 4 == 1) {\n            /* Family 1 is INET4 */\n            return addr.ipv4_addr.src_port;\n        } else {\n            /* Family 2 is INET6 */\n            return addr.ipv6_addr.src_port;\n        }\n    }\n\n    /* Returns [done, consumed] where done = false on failure */\n    std::pair<bool, unsigned int> parse(std::string_view data) {\n\n        /* We require at least four bytes to determine protocol */\n        if (data.length() < 4) {\n            return {false, 0};\n        }\n\n        /* HTTP can never start with \"\\r\\n\\r\\n\", but PROXY always does */\n        if (memcmp(data.data(), \"\\r\\n\\r\\n\", 4)) {\n            /* This is HTTP, so be done */\n            return {true, 0};\n        }\n\n        /* We assume we are parsing PROXY V2 here */\n\n        /* We require 16 bytes here */\n        if (data.length() < 16) {\n            return {false, 0};\n        }\n\n        /* Header is 16 bytes */\n        struct proxy_hdr_v2 header;\n        memcpy(&header, data.data(), 16);\n\n        if (memcmp(header.sig, \"\\x0D\\x0A\\x0D\\x0A\\x00\\x0D\\x0A\\x51\\x55\\x49\\x54\\x0A\", 12)) {\n            /* This is not PROXY protocol at all */\n            return {false, 0};\n        }\n\n        /* We only support version 2 */\n        if ((header.ver_cmd & 0xf0) >> 4 != 2) {\n            return {false, 0};\n        }\n\n        //printf(\"Version: %d\\n\", (header.ver_cmd & 0xf0) >> 4);\n        //printf(\"Command: %d\\n\", (header.ver_cmd & 0x0f));\n\n        /* We get length in network byte order (todo: share this function with the rest) */\n        uint16_t hostLength = _cond_byte_swap<uint16_t>(header.len);\n\n        /* We must have all the data available */\n        if (data.length() < 16u + hostLength) {\n            return {false, 0};\n        }\n\n        /* Payload cannot be more than sizeof proxy_addr */\n        if (sizeof(proxy_addr) < hostLength) {\n            return {false, 0};\n        }\n\n        //printf(\"Family: %d\\n\", (header.fam & 0xf0) >> 4);\n        //printf(\"Transport: %d\\n\", (header.fam & 0x0f));\n\n        /* We have 0 family by default, and UNSPEC is 0 as well */\n        family = header.fam;\n\n        /* Copy payload */\n        memcpy(&addr, data.data() + 16, hostLength);\n\n        /* We consumed everything */\n        return {true, 16 + hostLength};\n    }\n};\n\n}\n\n#endif\n\n#endif // UWS_PROXY_PARSER_H"
  },
  {
    "path": "src/QueryParser.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2020.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/* This module implements URI query parsing and retrieval of value given key */\n\n#ifndef UWS_QUERYPARSER_H\n#define UWS_QUERYPARSER_H\n\n#include <string_view>\n\nnamespace uWS {\n\n    /* Takes raw query including initial '?' sign. Will inplace decode, so input will mutate */\n    static inline std::string_view getDecodedQueryValue(std::string_view key, std::string_view rawQuery) {\n\n        /* Can't have a value without a key */\n        if (!key.length()) {\n            return {};\n        }\n\n        /* Start with the whole querystring including initial '?' */\n        std::string_view queryString = rawQuery;\n\n        /* List of key, value could be cached for repeated fetches similar to how headers are, todo! */\n        while (queryString.length()) {\n            /* Find boundaries of this statement */\n            std::string_view statement = queryString.substr(1, queryString.find('&', 1) - 1);\n\n            /* Only bother if first char of key match (early exit) */\n            if (statement.length() && statement[0] == key[0]) {\n                /* Equal sign must be present and not in the end of statement */\n                auto equality = statement.find('=');\n                if (equality != std::string_view::npos) {\n\n                    std::string_view statementKey = statement.substr(0, equality);\n                    std::string_view statementValue = statement.substr(equality + 1);\n\n                    /* String comparison */\n                    if (key == statementKey) {\n\n                        /* Decode value inplace, put null at end if before length of original */\n                        char *in = (char *) statementValue.data();\n\n                        /* Write offset */\n                        unsigned int out = 0;\n\n                        /* Walk over all chars until end or null char, decoding in place */\n                        for (unsigned int i = 0; i < statementValue.length() && in[i]; i++) {\n                                /* Only bother with '%' */\n                                if (in[i] == '%') {\n                                    /* Do we have enough data for two bytes hex? */\n                                    if (i + 2 >= statementValue.length()) {\n                                        return {};\n                                    }\n\n                                    /* Two bytes hex */\n                                    int hex1 = in[i + 1] - '0';\n                                    if (hex1 > 9) {\n                                        hex1 &= 223;\n                                        hex1 -= 7;\n                                    }\n\n                                    int hex2 = in[i + 2] - '0';\n                                    if (hex2 > 9) {\n                                        hex2 &= 223;\n                                        hex2 -= 7;\n                                    }\n\n                                    *((unsigned char *) &in[out]) = (unsigned char) (hex1 * 16 + hex2);\n                                    i += 2;\n                                } else {\n                                    /* Is this even a rule? */\n                                    if (in[i] == '+') {\n                                        in[out] = ' ';\n                                    } else {\n                                        in[out] = in[i];\n                                    }\n                                }\n\n                                /* We always only write one char */\n                                out++;\n                        }\n\n                        /* If decoded string is shorter than original, put null char to stop next read */\n                        if (out < statementValue.length()) {\n                            in[out] = 0;\n                        }\n\n                        return statementValue.substr(0, out);\n                    }\n                } else {\n                    /* This querystring is invalid, cannot parse it */\n                    return {nullptr, 0};\n                }\n            }\n\n            queryString.remove_prefix(statement.length() + 1);\n        }\n\n        /* Nothing found is given as nullptr, while empty string is given as some pointer to the given buffer */\n        return {nullptr, 0};\n    }\n\n}\n\n#endif\n"
  },
  {
    "path": "src/TopicTree.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2021.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef UWS_TOPICTREE_H\n#define UWS_TOPICTREE_H\n\n#include <map>\n#include <list>\n#include <iostream>\n#include <unordered_set>\n#include <utility>\n#include <memory>\n#include <unordered_map>\n#include <vector>\n#include <string_view>\n#include <functional>\n#include <set>\n#include <string>\n#include <exception>\n\nnamespace uWS {\n\nstruct Subscriber;\n\nstruct Topic : std::unordered_set<Subscriber *> {\n\n    Topic(std::string_view topic) : name(topic) {\n\n    }\n\n    std::string name;\n};\n\nstruct Subscriber {\n\n    template <typename, typename> friend struct TopicTree;\n\nprivate:\n    /* We use a factory */\n    Subscriber() = default;\n\n    /* State of prev, next does not matter unless we are needsDrainage() since we are not in the list */\n    Subscriber *prev, *next;\n\n    /* Any one subscriber can be part of at most 32 publishes before it needs a drain,\n     * or whatever encoding of runs or whatever we might do in the future */\n    uint16_t messageIndices[32];\n\n    /* This one matters the most, if it is 0 we are not in the list of drainableSubscribers */\n    unsigned char numMessageIndices = 0;\n\npublic:\n\n    /* We have a list of topics we subscribe to (read by WebSocket::iterateTopics) */\n    std::set<Topic *> topics;\n\n    /* User data */\n    void *user;\n\n    bool needsDrainage() {\n        return numMessageIndices;\n    }\n};\n\ntemplate <typename T, typename B>\nstruct TopicTree {\n\n    enum IteratorFlags {\n        LAST = 1,\n        FIRST = 2\n    };\n\n    /* Whomever is iterating this topic is locked to not modify its own list */\n    Subscriber *iteratingSubscriber = nullptr;\n\nprivate:\n\n    /* The drain callback must not publish, unsubscribe or subscribe.\n     * It must only cork, uncork, send, write */\n    std::function<bool(Subscriber *, T &, IteratorFlags)> cb;\n\n    /* The topics */\n    std::unordered_map<std::string_view, std::unique_ptr<Topic>> topics;\n\n    /* List of subscribers that needs drainage */\n    Subscriber *drainableSubscribers = nullptr;\n\n    /* Palette of outgoing messages, up to 64k */\n    std::vector<T> outgoingMessages;\n\n    void checkIteratingSubscriber(Subscriber *s) {\n        /* Notify user that they are doing something wrong here */\n        if (iteratingSubscriber == s) {\n            std::cerr << \"Error: WebSocket must not subscribe or unsubscribe to topics while iterating its topics!\" << std::endl;\n            std::terminate();\n        }\n    }\n\n    /* Warning: does NOT unlink from drainableSubscribers or modify next, prev. */\n    void drainImpl(Subscriber *s) {\n        /* Before we call cb we need to make sure this subscriber will not report needsDrainage()\n         * since WebSocket::send will call drain from within the cb in that case.*/\n        int numMessageIndices = s->numMessageIndices;\n        s->numMessageIndices = 0;\n\n        /* Then we emit cb */\n        for (int i = 0; i < numMessageIndices; i++) {\n            T &outgoingMessage = outgoingMessages[s->messageIndices[i]];\n\n            int flags = (i == numMessageIndices - 1) ? LAST : 0;\n\n            /* Returning true will stop drainage short (such as when backpressure is too high) */\n            if (cb(s, outgoingMessage, (IteratorFlags)(flags | (i == 0 ? FIRST : 0)))) {\n                break;\n            }\n        }\n    }\n\n    void unlinkDrainableSubscriber(Subscriber *s) {\n        if (s->prev) {\n            s->prev->next = s->next;\n        }\n        if (s->next) {\n            s->next->prev = s->prev;\n        }\n        /* If we are the head, then we also need to reset the head */\n        if (drainableSubscribers == s) {\n            drainableSubscribers = s->next;\n        }\n    }\n\npublic:\n\n    TopicTree(std::function<bool(Subscriber *, T &, IteratorFlags)> cb) : cb(cb) {\n\n    }\n\n    /* Returns nullptr if not found */\n    Topic *lookupTopic(std::string_view topic) {\n        auto it = topics.find(topic);\n        if (it == topics.end()) {\n            return nullptr;\n        }\n        return it->second.get();\n    }\n\n    /* Subscribe fails if we already are subscribed */\n    Topic *subscribe(Subscriber *s, std::string_view topic) {\n        /* Notify user that they are doing something wrong here */\n        checkIteratingSubscriber(s);\n\n        /* Lookup or create new topic */\n        Topic *topicPtr = lookupTopic(topic);\n        if (!topicPtr) {\n            Topic *newTopic = new Topic(topic);\n            topics.insert({std::string_view(newTopic->name.data(), newTopic->name.length()), std::unique_ptr<Topic>(newTopic)});\n            topicPtr = newTopic;\n        }\n\n        /* Insert us in topic, insert topic in us */\n        auto [it, inserted] = s->topics.insert(topicPtr);\n        if (!inserted) {\n            return nullptr;\n        }\n        topicPtr->insert(s);\n\n        /* Success */\n        return topicPtr;\n    }\n\n    /* Returns ok, last, newCount */\n    std::tuple<bool, bool, int> unsubscribe(Subscriber *s, std::string_view topic) {\n        /* Notify user that they are doing something wrong here */\n        checkIteratingSubscriber(s);\n\n        /* Lookup topic */\n        Topic *topicPtr = lookupTopic(topic);\n        if (!topicPtr) {\n            /* If the topic doesn't exist we are assumed to still be subscribers of something */\n            return {false, false, -1};\n        }\n\n        /* Erase from our list first */\n        if (s->topics.erase(topicPtr) == 0) {\n            return {false, false, -1};\n        }\n\n        /* Remove us from topic */\n        topicPtr->erase(s);\n\n        int newCount = (int) topicPtr->size();\n\n        /* If there is no subscriber to this topic, remove it */\n        if (!topicPtr->size()) {\n            /* Unique_ptr deletes the topic */\n            topics.erase(topic);\n        }\n\n        /* If we don't hold any topics we are to be freed altogether */\n        return {true, s->topics.size() == 0, newCount};\n    }\n\n    /* Factory function for creating a Subscriber */\n    Subscriber *createSubscriber() {\n        return new Subscriber();\n    }\n\n    /* This is used to end a Subscriber, before freeing it */\n    void freeSubscriber(Subscriber *s) {\n\n        /* I guess we call this one even if we are not subscribers */\n        if (!s) {\n            return;\n        }\n\n        /* For all topics, unsubscribe */\n        for (Topic *topicPtr : s->topics) {\n            /* If we are the last subscriber, simply remove the whole topic */\n            if (topicPtr->size() == 1) {\n                topics.erase(topicPtr->name);\n            } else {\n                /* Otherwise just remove us */\n                topicPtr->erase(s);\n            }\n        }\n\n        /* We also need to unlink us */\n        if (s->needsDrainage()) {\n            unlinkDrainableSubscriber(s);\n        }\n\n        delete s;\n    }\n\n    /* Mainly used by WebSocket::send to drain one socket before sending */\n    void drain(Subscriber *s) {\n        /* The list is undefined and cannot be touched unless needsDrainage(). */\n        if (s->needsDrainage()) {\n            /* This function differs from drainImpl by properly unlinking\n            * the subscriber from drainableSubscribers. drainImpl does not. */\n            unlinkDrainableSubscriber(s);\n\n            /* This one always resets needsDrainage before it calls any cb's.\n             * Otherwise we would stackoverflow when sending after publish but before drain. */\n            drainImpl(s);\n            \n            /* If we drained last subscriber, also clear outgoingMessages */\n            if (!drainableSubscribers) {\n                outgoingMessages.clear();\n            }\n        }\n    }\n\n    /* Called everytime we call send, to drain published messages so to sync outgoing messages */\n    void drain() {\n        if (drainableSubscribers) {\n            /* Drain one socket a time */\n            for (Subscriber *s = drainableSubscribers; s; s = s->next) {\n                /* Instead of unlinking every single subscriber, we just leave the list undefined\n                 * and reset drainableSubscribers ptr below. */\n                drainImpl(s);\n            }\n            /* Drain always clears drainableSubscribers and outgoingMessages */\n            drainableSubscribers = nullptr;\n            outgoingMessages.clear();\n        }\n    }\n\n    /* Big messages bypass all buffering and land directly in backpressure */\n    template <typename F>\n    bool publishBig(Subscriber *sender, std::string_view topic, B &&bigMessage, F cb) {\n        /* Do we even have this topic? */\n        auto it = topics.find(topic);\n        if (it == topics.end()) {\n            return false;\n        }\n\n        /* For all subscribers in topic */\n        for (Subscriber *s : *it->second) {\n\n            /* If we are sender then ignore us */\n            if (sender != s) {\n                cb(s, bigMessage);\n            }\n        }\n\n        return true;\n    }\n\n    /* Linear in number of affected subscribers */\n    bool publish(Subscriber *sender, std::string_view topic, T &&message) {\n        /* Do we even have this topic? */\n        auto it = topics.find(topic);\n        if (it == topics.end()) {\n            return false;\n        }\n\n        /* If we have more than 65k messages we need to drain every socket. */\n        if (outgoingMessages.size() == UINT16_MAX) {\n            /* If there is a socket that is currently corked, this will be ugly as all sockets will drain\n             * to their own backpressure */\n            drain();\n        }\n\n        /* If nobody references this message, don't buffer it */\n        bool referencedMessage = false;\n\n        /* For all subscribers in topic */\n        for (Subscriber *s : *it->second) {\n\n            /* If we are sender then ignore us */\n            if (sender != s) {\n\n                /* At least one subscriber wants this message */\n                referencedMessage = true;\n\n                /* If we already have too many outgoing messages on this subscriber, drain it now */\n                if (s->numMessageIndices == 32) {\n                    /* This one does not need to check needsDrainage here but still does. */\n                    drain(s);\n                }\n\n                /* Finally we can continue */\n                s->messageIndices[s->numMessageIndices++] = (uint16_t)outgoingMessages.size();\n                /* First message adds subscriber to list of drainable subscribers */\n                if (s->numMessageIndices == 1) {\n                    /* Insert us in the head of drainable subscribers */\n                    s->next = drainableSubscribers;\n                    s->prev = nullptr;\n                    if (s->next) {\n                        s->next->prev = s;\n                    }\n                    drainableSubscribers = s;\n                }\n            }\n        }\n\n        /* Push this message and return with success */\n        if (referencedMessage) {\n            outgoingMessages.emplace_back(message);\n        }\n\n        /* Success if someone wants it */\n        return referencedMessage;\n    }\n};\n\n}\n\n#endif\n"
  },
  {
    "path": "src/Utilities.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2020.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef UWS_UTILITIES_H\n#define UWS_UTILITIES_H\n\n/* Various common utilities */\n\n#include <cstdint>\n\nnamespace uWS {\nnamespace utils {\n\ninline int u32toaHex(uint32_t value, char *dst) {\n    char palette[] = \"0123456789abcdef\";\n    char temp[10];\n    char *p = temp;\n    do {\n        *p++ = palette[value & 15];\n        value >>= 4;\n    } while (value > 0);\n\n    int ret = (int) (p - temp);\n\n    do {\n        *dst++ = *--p;\n    } while (p != temp);\n\n    return ret;\n}\n\ninline int u64toa(uint64_t value, char *dst) {\n    char temp[20];\n    char *p = temp;\n    do {\n        *p++ = (char) ((value % 10) + '0');\n        value /= 10;\n    } while (value > 0);\n\n    int ret = (int) (p - temp);\n\n    do {\n        *dst++ = *--p;\n    } while (p != temp);\n\n    return ret;\n}\n\n}\n}\n\n#endif // UWS_UTILITIES_H\n"
  },
  {
    "path": "src/WebSocket.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2021.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef UWS_WEBSOCKET_H\n#define UWS_WEBSOCKET_H\n\n#include \"WebSocketData.h\"\n#include \"WebSocketProtocol.h\"\n#include \"AsyncSocket.h\"\n#include \"WebSocketContextData.h\"\n\n#include <string_view>\n\nnamespace uWS {\n\n/* Experimental */\nenum CompressFlags : int {\n    NO_ACTION,\n    COMPRESS,\n    ALREADY_COMPRESSED\n};\n\ntemplate <bool SSL, bool isServer, typename USERDATA>\nstruct WebSocket : AsyncSocket<SSL> {\n    template <bool> friend struct TemplatedApp;\n    template <bool> friend struct HttpResponse;\nprivate:\n    typedef AsyncSocket<SSL> Super;\n\n    void *init(bool perMessageDeflate, CompressOptions compressOptions, BackPressure &&backpressure) {\n        new (us_socket_ext(SSL, (us_socket_t *) this)) WebSocketData(perMessageDeflate, compressOptions, std::move(backpressure));\n        return this;\n    }\npublic:\n\n    /* Returns pointer to the per socket user data */\n    USERDATA *getUserData() {\n        WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) this);\n        /* We just have it overallocated by sizeof type */\n        return (USERDATA *) (webSocketData + 1);\n    }\n\n    /* See AsyncSocket */\n    using Super::getBufferedAmount;\n    using Super::getRemoteAddress;\n    using Super::getRemoteAddressAsText;\n    using Super::getRemotePort;\n    using Super::getNativeHandle;\n\n    /* WebSocket close cannot be an alias to AsyncSocket::close since\n     * we need to check first if it was shut down by remote peer */\n    us_socket_t *close() {\n        if (us_socket_is_closed(SSL, (us_socket_t *) this)) {\n            return nullptr;\n        }\n        WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData();\n        if (webSocketData->isShuttingDown) {\n            return nullptr;\n        }\n\n        return us_socket_close(SSL, (us_socket_t *) this, 0, nullptr);\n    }\n\n    enum SendStatus : int {\n        BACKPRESSURE,\n        SUCCESS,\n        DROPPED\n    };\n\n    /* Sending fragmented messages puts a bit of effort on the user; you must not interleave regular sends\n     * with fragmented sends and you must sendFirstFragment, [sendFragment], then finally sendLastFragment. */\n    SendStatus sendFirstFragment(std::string_view message, OpCode opCode = OpCode::BINARY, bool compress = false) {\n        return send(message, opCode, compress, false);\n    }\n\n    SendStatus sendFragment(std::string_view message, bool compress = false) {\n        return send(message, CONTINUATION, compress, false);\n    }\n\n    SendStatus sendLastFragment(std::string_view message, bool compress = false) {\n        return send(message, CONTINUATION, compress, true);\n    }\n\n    /* Experimental */\n    bool hasNegotiatedCompression() {\n        WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData();\n        return webSocketData->compressionStatus == WebSocketData::ENABLED;\n    }\n\n    /* Experimental */\n    SendStatus sendPrepared(PreparedMessage &preparedMessage) {\n        if (preparedMessage.compressed && hasNegotiatedCompression() && preparedMessage.compressedMessage.length() < preparedMessage.originalMessage.length()) {\n            return send({preparedMessage.compressedMessage.data(), preparedMessage.compressedMessage.length()}, (OpCode) preparedMessage.opCode, uWS::CompressFlags::ALREADY_COMPRESSED);\n        }\n        return send({preparedMessage.originalMessage.data(), preparedMessage.originalMessage.length()}, (OpCode) preparedMessage.opCode);\n    }\n\n    /* Send or buffer a WebSocket frame, compressed or not. Returns BACKPRESSURE on increased user space backpressure,\n     * DROPPED on dropped message (due to backpressure) or SUCCCESS if you are free to send even more now. */\n    SendStatus send(std::string_view message, OpCode opCode = OpCode::BINARY, int compress = false, bool fin = true) {\n        WebSocketContextData<SSL, USERDATA> *webSocketContextData = (WebSocketContextData<SSL, USERDATA> *) us_socket_context_ext(SSL,\n            (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this)\n        );\n\n        /* Skip sending and report success if we are over the limit of maxBackpressure */\n        if (webSocketContextData->maxBackpressure && webSocketContextData->maxBackpressure < getBufferedAmount()) {\n            /* Also defer a close if we should */\n            if (webSocketContextData->closeOnBackpressureLimit) {\n                us_socket_shutdown_read(SSL, (us_socket_t *) this);\n            }\n\n            /* It is okay to call send again from within this callback since we immediately return with DROPPED afterwards */\n            if (webSocketContextData->droppedHandler) {\n                webSocketContextData->droppedHandler(this, message, opCode);\n            }\n\n            return DROPPED;\n        }\n\n        /* If we are subscribers and have messages to drain we need to drain them here to stay synced */\n        WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData();\n\n        /* Special path for long sends of non-compressed, non-SSL messages */\n        if (message.length() >= 16 * 1024 && !compress && !SSL && !webSocketData->subscriber && getBufferedAmount() == 0 && Super::getLoopData()->corkOffset == 0) {\n            char header[10];\n            int header_length = (int) protocol::formatMessage<isServer>(header, \"\", 0, opCode, message.length(), compress, fin);\n            int written = us_socket_write2(0, (struct us_socket_t *)this, header, header_length, message.data(), (int) message.length());\n        \n            if (written != header_length + (int) message.length()) {\n                /* Buffer up backpressure */\n                if (written > header_length) {\n                    webSocketData->buffer.append(message.data() + written - header_length, message.length() - (size_t) (written - header_length));\n                } else {\n                    webSocketData->buffer.append(header + written, (size_t) header_length - (size_t) written);\n                    webSocketData->buffer.append(message.data(), message.length());\n                }\n                /* We cannot still be corked if we have backpressure.\n                 * We also cannot uncork normally since it will re-write the already buffered\n                 * up backpressure again. */\n                Super::uncorkWithoutSending();\n                return BACKPRESSURE;\n            }\n        } else {\n\n            if (webSocketData->subscriber) {\n                /* This will call back into us, send. */\n                webSocketContextData->topicTree->drain(webSocketData->subscriber);\n            }\n\n            /* Transform the message to compressed domain if requested */\n            if (compress) {\n                WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData();\n\n                /* Check and correct the compress hint. It is never valid to compress 0 bytes */\n                if (message.length() && opCode < 3 && webSocketData->compressionStatus == WebSocketData::ENABLED) {\n                    /* If compress is 2 (IS_PRE_COMPRESSED), skip this step (experimental) */\n                    if (compress != CompressFlags::ALREADY_COMPRESSED) {\n                        LoopData *loopData = Super::getLoopData();\n                        /* Compress using either shared or dedicated deflationStream */\n                        if (webSocketData->deflationStream) {\n                            message = webSocketData->deflationStream->deflate(loopData->zlibContext, message, false);\n                        } else {\n                            message = loopData->deflationStream->deflate(loopData->zlibContext, message, true);\n                        }\n                    }\n                } else {\n                    compress = false;\n                }\n            }\n\n            /* Get size, allocate size, write if needed */\n            size_t messageFrameSize = protocol::messageFrameSize(message.length());\n            auto [sendBuffer, sendBufferAttribute] = Super::getSendBuffer(messageFrameSize);\n            protocol::formatMessage<isServer>(sendBuffer, message.data(), message.length(), opCode, message.length(), compress, fin);\n\n            /* Depending on size of message we have different paths */\n            if (sendBufferAttribute == SendBufferAttribute::NEEDS_DRAIN) {\n                /* This is a drain */\n                auto[written, failed] = Super::write(nullptr, 0);\n                if (failed) {\n                    /* Return false for failure, skipping to reset the timeout below */\n                    return BACKPRESSURE;\n                }\n            } else if (sendBufferAttribute == SendBufferAttribute::NEEDS_UNCORK) {\n                /* Uncork if we came here uncorked */\n                auto [written, failed] = Super::uncork();\n                if (failed) {\n                    return BACKPRESSURE;\n                }\n            }\n\n        }\n\n        /* Every successful send resets the timeout */\n        if (webSocketContextData->resetIdleTimeoutOnSend) {\n            Super::timeout(webSocketContextData->idleTimeoutComponents.first);\n            WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData();\n            webSocketData->hasTimedOut = false;\n        }\n\n        /* Return success */\n        return SUCCESS;\n    }\n\n    /* Send websocket close frame, emit close event, send FIN if successful.\n     * Will not append a close reason if code is 0 or 1005. */\n    void end(int code = 0, std::string_view message = {}) {\n        /* Check if we already called this one */\n        WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) this);\n        if (webSocketData->isShuttingDown) {\n            return;\n        }\n\n        /* We postpone any FIN sending to either drainage or uncorking */\n        webSocketData->isShuttingDown = true;\n\n        /* Format and send the close frame */\n        static const int MAX_CLOSE_PAYLOAD = 123;\n        size_t length = std::min<size_t>(MAX_CLOSE_PAYLOAD, message.length());\n        char closePayload[MAX_CLOSE_PAYLOAD + 2];\n        size_t closePayloadLength = protocol::formatClosePayload(closePayload, (uint16_t) code, message.data(), length);\n        bool ok = send(std::string_view(closePayload, closePayloadLength), OpCode::CLOSE);\n\n        /* FIN if we are ok and not corked */\n        if (!this->isCorked()) {\n            if (ok) {\n                /* If we are not corked, and we just sent off everything, we need to FIN right here.\n                 * In all other cases, we need to fin either if uncork was successful, or when drainage is complete. */\n                this->shutdown();\n            }\n        }\n\n        WebSocketContextData<SSL, USERDATA> *webSocketContextData = (WebSocketContextData<SSL, USERDATA> *) us_socket_context_ext(SSL,\n            (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this)\n        );\n\n        /* Set shorter timeout (use ping-timeout) to avoid long hanging sockets after end() on broken connections */\n        Super::timeout(webSocketContextData->idleTimeoutComponents.second);\n\n        /* At this point we iterate all currently held subscriptions and emit an event for all of them */\n        if (webSocketData->subscriber && webSocketContextData->subscriptionHandler) {\n            for (Topic *t : webSocketData->subscriber->topics) {\n                webSocketContextData->subscriptionHandler(this, t->name, (int) t->size() - 1, (int) t->size());\n            }\n        }\n\n        /* Make sure to unsubscribe from any pub/sub node at exit */\n        webSocketContextData->topicTree->freeSubscriber(webSocketData->subscriber);\n        webSocketData->subscriber = nullptr;\n\n        /* Emit close event */\n        if (webSocketContextData->closeHandler) {\n            webSocketContextData->closeHandler(this, code, message);\n        }\n        ((USERDATA *) this->getUserData())->~USERDATA();\n    }\n\n    /* Corks the response if possible. Leaves already corked socket be. */\n    void cork(MoveOnlyFunction<void()> &&handler) {\n        if (!Super::isCorked() && Super::canCork()) {\n            Super::cork();\n            handler();\n\n            /* There is no timeout when failing to uncork for WebSockets,\n             * as that is handled by idleTimeout */\n            auto [written, failed] = Super::uncork();\n            (void)written;\n            (void)failed;\n        } else {\n            /* We are already corked, or can't cork so let's just call the handler */\n            handler();\n        }\n    }\n\n    /* Subscribe to a topic according to MQTT rules and syntax. Returns success */\n    bool subscribe(std::string_view topic, bool = false) {\n        WebSocketContextData<SSL, USERDATA> *webSocketContextData = (WebSocketContextData<SSL, USERDATA> *) us_socket_context_ext(SSL,\n            (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this)\n        );\n\n        /* Make us a subscriber if we aren't yet */\n        WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) this);\n        if (!webSocketData->subscriber) {\n            webSocketData->subscriber = webSocketContextData->topicTree->createSubscriber();\n            webSocketData->subscriber->user = this;\n        }\n\n        /* Cannot return numSubscribers as this is only for this particular websocket context */\n        Topic *topicOrNull = webSocketContextData->topicTree->subscribe(webSocketData->subscriber, topic);\n        if (topicOrNull && webSocketContextData->subscriptionHandler) {\n            /* Emit this socket, the topic, new count, old count */\n            webSocketContextData->subscriptionHandler(this, topic, (int) topicOrNull->size(), (int) topicOrNull->size() - 1);\n        }\n\n        /* Subscribe always succeeds */\n        return true;\n    }\n\n    /* Unsubscribe from a topic, returns true if we were subscribed. */\n    bool unsubscribe(std::string_view topic, bool = false) {\n        WebSocketContextData<SSL, USERDATA> *webSocketContextData = (WebSocketContextData<SSL, USERDATA> *) us_socket_context_ext(SSL,\n            (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this)\n        );\n\n        WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) this);\n        \n        if (!webSocketData->subscriber) { return false; }\n\n        /* Cannot return numSubscribers as this is only for this particular websocket context */\n        auto [ok, last, newCount] = webSocketContextData->topicTree->unsubscribe(webSocketData->subscriber, topic);\n        /* Emit subscription event if last */\n        if (ok && webSocketContextData->subscriptionHandler) {\n            webSocketContextData->subscriptionHandler(this, topic, newCount, newCount + 1);\n        }\n\n        /* Leave us as subscribers even if we subscribe to nothing (last unsubscribed topic might miss its message otherwise) */\n\n        return ok;\n    }\n\n    /* Returns whether this socket is subscribed to the specified topic */\n    bool isSubscribed(std::string_view topic) {\n        WebSocketContextData<SSL, USERDATA> *webSocketContextData = (WebSocketContextData<SSL, USERDATA> *) us_socket_context_ext(SSL,\n            (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this)\n        );\n\n        WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) this);\n        if (!webSocketData->subscriber) {\n            return false;\n        }\n\n        Topic *topicPtr = webSocketContextData->topicTree->lookupTopic(topic);\n        if (!topicPtr) {\n            return false;\n        }\n\n        return topicPtr->count(webSocketData->subscriber);\n    }\n\n    /* Iterates all topics of this WebSocket. Every topic is represented by its full name.\n     * Can be called in close handler. It is possible to modify the subscription list while\n     * inside the callback ONLY IF not modifying the topic passed to the callback.\n     * Topic names are valid only for the duration of the callback. */\n    void iterateTopics(MoveOnlyFunction<void(std::string_view)> cb) {\n        WebSocketContextData<SSL, USERDATA> *webSocketContextData = (WebSocketContextData<SSL, USERDATA> *) us_socket_context_ext(SSL,\n            (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this)\n        );\n\n        WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) this);\n        if (webSocketData->subscriber) {\n            /* Lock this subscriber for unsubscription / subscription */\n            webSocketContextData->topicTree->iteratingSubscriber = webSocketData->subscriber;\n\n            for (Topic *topicPtr : webSocketData->subscriber->topics) {\n                cb({topicPtr->name.data(), topicPtr->name.length()});\n            }\n\n            /* Unlock subscriber */\n            webSocketContextData->topicTree->iteratingSubscriber = nullptr;\n        }\n    }\n\n    /* Publish a message to a topic according to MQTT rules and syntax. Returns success.\n     * We, the WebSocket, must be subscribed to the topic itself and if so - no message will be sent to ourselves.\n     * Use App::publish for an unconditional publish that simply publishes to whomever might be subscribed. */\n    bool publish(std::string_view topic, std::string_view message, OpCode opCode = OpCode::TEXT, bool compress = false) {\n        WebSocketContextData<SSL, USERDATA> *webSocketContextData = (WebSocketContextData<SSL, USERDATA> *) us_socket_context_ext(SSL,\n            (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this)\n        );\n\n        /* We cannot be a subscriber of this topic if we are not a subscriber of anything */\n        WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) this);\n        if (!webSocketData->subscriber) {\n            /* Failure, but still do return the number of subscribers */\n            return false;\n        }\n\n        /* Publish as sender, does not receive its own messages even if subscribed to relevant topics */\n        if (message.length() >= LoopData::CORK_BUFFER_SIZE) {\n            return webSocketContextData->topicTree->publishBig(webSocketData->subscriber, topic, {message, opCode, compress}, [](Subscriber *s, TopicTreeBigMessage &message) {\n                auto *ws = (WebSocket<SSL, true, int> *) s->user;\n\n                ws->send(message.message, (OpCode)message.opCode, message.compress);\n            });\n        } else {\n            return webSocketContextData->topicTree->publish(webSocketData->subscriber, topic, {std::string(message), opCode, compress});\n        }\n    }\n};\n\n}\n\n#endif // UWS_WEBSOCKET_H\n"
  },
  {
    "path": "src/WebSocketContext.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2020.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef UWS_WEBSOCKETCONTEXT_H\n#define UWS_WEBSOCKETCONTEXT_H\n\n#include \"WebSocketContextData.h\"\n#include \"WebSocketProtocol.h\"\n#include \"WebSocketData.h\"\n#include \"WebSocket.h\"\n\nnamespace uWS {\n\ntemplate <bool SSL, bool isServer, typename USERDATA>\nstruct WebSocketContext {\n    template <bool> friend struct TemplatedApp;\n    template <bool, typename> friend struct WebSocketProtocol;\nprivate:\n    WebSocketContext() = delete;\n\n    us_socket_context_t *getSocketContext() {\n        return (us_socket_context_t *) this;\n    }\n\n    WebSocketContextData<SSL, USERDATA> *getExt() {\n        return (WebSocketContextData<SSL, USERDATA> *) us_socket_context_ext(SSL, (us_socket_context_t *) this);\n    }\n\n    /* If we have negotiated compression, set this frame compressed */\n    static bool setCompressed(WebSocketState<isServer> */*wState*/, void *s) {\n        WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) s);\n\n        if (webSocketData->compressionStatus == WebSocketData::CompressionStatus::ENABLED) {\n            webSocketData->compressionStatus = WebSocketData::CompressionStatus::COMPRESSED_FRAME;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    static void forceClose(WebSocketState<isServer> */*wState*/, void *s, std::string_view reason = {}) {\n        us_socket_close(SSL, (us_socket_t *) s, (int) reason.length(), (void *) reason.data());\n    }\n\n    /* Returns true on breakage */\n    static bool handleFragment(char *data, size_t length, unsigned int remainingBytes, int opCode, bool fin, WebSocketState<isServer> *webSocketState, void *s) {\n        /* WebSocketData and WebSocketContextData */\n        WebSocketContextData<SSL, USERDATA> *webSocketContextData = (WebSocketContextData<SSL, USERDATA> *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s));\n        WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) s);\n\n        /* Is this a non-control frame? */\n        if (opCode < 3) {\n            /* Did we get everything in one go? */\n            if (!remainingBytes && fin && !webSocketData->fragmentBuffer.length()) {\n\n                /* Handle compressed frame */\n                if (webSocketData->compressionStatus == WebSocketData::CompressionStatus::COMPRESSED_FRAME) {\n                        webSocketData->compressionStatus = WebSocketData::CompressionStatus::ENABLED;\n\n                        LoopData *loopData = (LoopData *) us_loop_ext(us_socket_context_loop(SSL, us_socket_context(SSL, (us_socket_t *) s)));\n                        /* Decompress using shared or dedicated decompressor */\n                        std::optional<std::string_view> inflatedFrame;\n                        if (webSocketData->inflationStream) {\n                            inflatedFrame = webSocketData->inflationStream->inflate(loopData->zlibContext, {data, length}, webSocketContextData->maxPayloadLength, false);\n                        } else {\n                            inflatedFrame = loopData->inflationStream->inflate(loopData->zlibContext, {data, length}, webSocketContextData->maxPayloadLength, true);\n                        }\n\n                        if (!inflatedFrame.has_value()) {\n                            forceClose(webSocketState, s, ERR_TOO_BIG_MESSAGE_INFLATION);\n                            return true;\n                        } else {\n                            data = (char *) inflatedFrame->data();\n                            length = inflatedFrame->length();\n                        }\n                }\n\n                /* Check text messages for Utf-8 validity */\n                if (opCode == 1 && !protocol::isValidUtf8((unsigned char *) data, length)) {\n                    forceClose(webSocketState, s, ERR_INVALID_TEXT);\n                    return true;\n                }\n\n                /* Emit message event & break if we are closed or shut down when returning */\n                if (webSocketContextData->messageHandler) {\n                    webSocketContextData->messageHandler((WebSocket<SSL, isServer, USERDATA> *) s, std::string_view(data, length), (OpCode) opCode);\n                    if (us_socket_is_closed(SSL, (us_socket_t *) s) || webSocketData->isShuttingDown) {\n                        return true;\n                    }\n                }\n            } else {\n                /* Allocate fragment buffer up front first time */\n                if (!webSocketData->fragmentBuffer.length()) {\n                    webSocketData->fragmentBuffer.reserve(length + remainingBytes);\n                }\n                /* Fragments forming a big message are not caught until appending them */\n                if (refusePayloadLength(length + webSocketData->fragmentBuffer.length(), webSocketState, s)) {\n                    forceClose(webSocketState, s, ERR_TOO_BIG_MESSAGE);\n                    return true;\n                }\n                webSocketData->fragmentBuffer.append(data, length);\n\n                /* Are we done now? */\n                // todo: what if we don't have any remaining bytes yet we are not fin? forceclose!\n                if (!remainingBytes && fin) {\n\n                    /* Handle compression */\n                    if (webSocketData->compressionStatus == WebSocketData::CompressionStatus::COMPRESSED_FRAME) {\n                            webSocketData->compressionStatus = WebSocketData::CompressionStatus::ENABLED;\n\n                            /* 9 bytes of padding for libdeflate, 4 for zlib */\n                            webSocketData->fragmentBuffer.append(\"123456789\");\n\n                            LoopData *loopData = (LoopData *) us_loop_ext(\n                                us_socket_context_loop(SSL,\n                                    us_socket_context(SSL, (us_socket_t *) s)\n                                )\n                            );\n\n                            /* Decompress using shared or dedicated decompressor */\n                            std::optional<std::string_view> inflatedFrame;\n                            if (webSocketData->inflationStream) {\n                                inflatedFrame = webSocketData->inflationStream->inflate(loopData->zlibContext, {webSocketData->fragmentBuffer.data(), webSocketData->fragmentBuffer.length() - 9}, webSocketContextData->maxPayloadLength, false);\n                            } else {\n                                inflatedFrame = loopData->inflationStream->inflate(loopData->zlibContext, {webSocketData->fragmentBuffer.data(), webSocketData->fragmentBuffer.length() - 9}, webSocketContextData->maxPayloadLength, true);\n                            }\n\n                            if (!inflatedFrame.has_value()) {\n                                forceClose(webSocketState, s, ERR_TOO_BIG_MESSAGE_INFLATION);\n                                return true;\n                            } else {\n                                data = (char *) inflatedFrame->data();\n                                length = inflatedFrame->length();\n                            }\n\n\n                    } else {\n                        // reset length and data ptrs\n                        length = webSocketData->fragmentBuffer.length();\n                        data = webSocketData->fragmentBuffer.data();\n                    }\n\n                    /* Check text messages for Utf-8 validity */\n                    if (opCode == 1 && !protocol::isValidUtf8((unsigned char *) data, length)) {\n                        forceClose(webSocketState, s, ERR_INVALID_TEXT);\n                        return true;\n                    }\n\n                    /* Emit message and check for shutdown or close */\n                    if (webSocketContextData->messageHandler) {\n                        webSocketContextData->messageHandler((WebSocket<SSL, isServer, USERDATA> *) s, std::string_view(data, length), (OpCode) opCode);\n                        if (us_socket_is_closed(SSL, (us_socket_t *) s) || webSocketData->isShuttingDown) {\n                            return true;\n                        }\n                    }\n\n                    /* If we shutdown or closed, this will be taken care of elsewhere */\n                    webSocketData->fragmentBuffer.clear();\n                }\n            }\n        } else {\n            /* Control frames need the websocket to send pings, pongs and close */\n            WebSocket<SSL, isServer, USERDATA> *webSocket = (WebSocket<SSL, isServer, USERDATA> *) s;\n\n            if (!remainingBytes && fin && !webSocketData->controlTipLength) {\n                if (opCode == CLOSE) {\n                    auto closeFrame = protocol::parseClosePayload(data, length);\n                    webSocket->end(closeFrame.code, std::string_view(closeFrame.message, closeFrame.length));\n                    return true;\n                } else {\n                    if (opCode == PING) {\n                        webSocket->send(std::string_view(data, length), (OpCode) OpCode::PONG);\n                        if (webSocketContextData->pingHandler) {\n                            webSocketContextData->pingHandler(webSocket, {data, length});\n                            if (us_socket_is_closed(SSL, (us_socket_t *) s) || webSocketData->isShuttingDown) {\n                                return true;\n                            }\n                        }\n                    } else if (opCode == PONG) {\n                        if (webSocketContextData->pongHandler) {\n                            webSocketContextData->pongHandler(webSocket, {data, length});\n                            if (us_socket_is_closed(SSL, (us_socket_t *) s) || webSocketData->isShuttingDown) {\n                                return true;\n                            }\n                        }\n                    }\n                }\n            } else {\n                /* Here we never mind any size optimizations as we are in the worst possible path */\n                webSocketData->fragmentBuffer.append(data, length);\n                webSocketData->controlTipLength += (unsigned int) length;\n\n                if (!remainingBytes && fin) {\n                    char *controlBuffer = (char *) webSocketData->fragmentBuffer.data() + webSocketData->fragmentBuffer.length() - webSocketData->controlTipLength;\n                    if (opCode == CLOSE) {\n                        protocol::CloseFrame closeFrame = protocol::parseClosePayload(controlBuffer, webSocketData->controlTipLength);\n                        webSocket->end(closeFrame.code, std::string_view(closeFrame.message, closeFrame.length));\n                        return true;\n                    } else {\n                        if (opCode == PING) {\n                            webSocket->send(std::string_view(controlBuffer, webSocketData->controlTipLength), (OpCode) OpCode::PONG);\n                            if (webSocketContextData->pingHandler) {\n                                webSocketContextData->pingHandler(webSocket, std::string_view(controlBuffer, webSocketData->controlTipLength));\n                                if (us_socket_is_closed(SSL, (us_socket_t *) s) || webSocketData->isShuttingDown) {\n                                    return true;\n                                }\n                            }\n                        } else if (opCode == PONG) {\n                            if (webSocketContextData->pongHandler) {\n                                webSocketContextData->pongHandler(webSocket, std::string_view(controlBuffer, webSocketData->controlTipLength));\n                                if (us_socket_is_closed(SSL, (us_socket_t *) s) || webSocketData->isShuttingDown) {\n                                    return true;\n                                }\n                            }\n                        }\n                    }\n\n                    /* Same here, we do not care for any particular smart allocation scheme */\n                    webSocketData->fragmentBuffer.resize((unsigned int) webSocketData->fragmentBuffer.length() - webSocketData->controlTipLength);\n                    webSocketData->controlTipLength = 0;\n                }\n            }\n        }\n        return false;\n    }\n\n    static bool refusePayloadLength(uint64_t length, WebSocketState<isServer> */*wState*/, void *s) {\n        auto *webSocketContextData = (WebSocketContextData<SSL, USERDATA> *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s));\n\n        /* Return true for refuse, false for accept */\n        return webSocketContextData->maxPayloadLength < length;\n    }\n\n    WebSocketContext<SSL, isServer, USERDATA> *init() {\n        /* Adopting a socket does not trigger open event.\n         * We arreive as WebSocket with timeout set and\n         * any backpressure from HTTP state kept. */\n\n        /* Handle socket disconnections */\n        us_socket_context_on_close(SSL, getSocketContext(), [](auto *s, int code, void *reason) {\n            /* For whatever reason, if we already have emitted close event, do not emit it again */\n            WebSocketData *webSocketData = (WebSocketData *) (us_socket_ext(SSL, s));\n            if (!webSocketData->isShuttingDown) {\n                /* Emit close event */\n                auto *webSocketContextData = (WebSocketContextData<SSL, USERDATA> *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s));\n\n                /* At this point we iterate all currently held subscriptions and emit an event for all of them */\n                if (webSocketData->subscriber && webSocketContextData->subscriptionHandler) {\n                    for (Topic *t : webSocketData->subscriber->topics) {\n                        webSocketContextData->subscriptionHandler((WebSocket<SSL, isServer, USERDATA> *) s, t->name, (int) t->size() - 1, (int) t->size());\n                    }\n                }\n\n                /* Make sure to unsubscribe from any pub/sub node at exit */\n                webSocketContextData->topicTree->freeSubscriber(webSocketData->subscriber);\n                webSocketData->subscriber = nullptr;\n\n                auto *ws = (WebSocket<SSL, isServer, USERDATA> *) s;\n                if (webSocketContextData->closeHandler) {\n                    webSocketContextData->closeHandler(ws, 1006, {(char *) reason, (size_t) code});\n                }\n                ((USERDATA *) ws->getUserData())->~USERDATA();\n            }\n\n            /* Destruct in-placed data struct */\n            webSocketData->~WebSocketData();\n\n            return s;\n        });\n\n        /* Handle WebSocket data streams */\n        us_socket_context_on_data(SSL, getSocketContext(), [](auto *s, char *data, int length) {\n\n            /* We need the websocket data */\n            WebSocketData *webSocketData = (WebSocketData *) (us_socket_ext(SSL, s));\n\n            /* When in websocket shutdown mode, we do not care for ANY message, whether responding close frame or not.\n             * We only care for the TCP FIN really, not emitting any message after closing is key */\n            if (webSocketData->isShuttingDown) {\n                return s;\n            }\n\n            auto *webSocketContextData = (WebSocketContextData<SSL, USERDATA> *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s));\n            auto *asyncSocket = (AsyncSocket<SSL> *) s;\n\n            /* Every time we get data and not in shutdown state we simply reset the timeout */\n            asyncSocket->timeout(webSocketContextData->idleTimeoutComponents.first);\n            webSocketData->hasTimedOut = false;\n\n            /* We always cork on data */\n            asyncSocket->cork();\n\n            /* This parser has virtually no overhead */\n            WebSocketProtocol<isServer, WebSocketContext<SSL, isServer, USERDATA>>::consume(data, (unsigned int) length, (WebSocketState<isServer> *) webSocketData, s);\n\n            /* Uncorking a closed socekt is fine, in fact it is needed */\n            asyncSocket->uncork();\n\n            /* If uncorking was successful and we are in shutdown state then send TCP FIN */\n            if (asyncSocket->getBufferedAmount() == 0) {\n                /* We can now be in shutdown state */\n                if (webSocketData->isShuttingDown) {\n                    /* Shutting down a closed socket is handled by uSockets and just fine */\n                    asyncSocket->shutdown();\n                }\n            }\n\n            return s;\n        });\n\n        /* Handle HTTP write out (note: SSL_read may trigger this spuriously, the app need to handle spurious calls) */\n        us_socket_context_on_writable(SSL, getSocketContext(), [](auto *s) {\n\n            /* NOTE: Are we called here corked? If so, the below write code is broken, since\n             * we will have 0 as getBufferedAmount due to writing to cork buffer, then sending TCP FIN before\n             * we actually uncorked and sent off things */\n\n            /* It makes sense to check for us_is_shut_down here and return if so, to avoid shutting down twice */\n            if (us_socket_is_shut_down(SSL, (us_socket_t *) s)) {\n                return s;\n            }\n\n            AsyncSocket<SSL> *asyncSocket = (AsyncSocket<SSL> *) s;\n            WebSocketData *webSocketData = (WebSocketData *)(us_socket_ext(SSL, s));\n\n            /* We store old backpressure since it is unclear whether write drained anything,\n             * however, in case of coming here with 0 backpressure we still need to emit drain event */\n            unsigned int backpressure = asyncSocket->getBufferedAmount();\n\n            /* Drain as much as possible */\n            asyncSocket->write(nullptr, 0);\n\n            /* Behavior: if we actively drain backpressure, always reset timeout (even if we are in shutdown) */\n            /* Also reset timeout if we came here with 0 backpressure */\n            if (!backpressure || backpressure > asyncSocket->getBufferedAmount()) {\n                auto *webSocketContextData = (WebSocketContextData<SSL, USERDATA> *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s));\n                asyncSocket->timeout(webSocketContextData->idleTimeoutComponents.first);\n                webSocketData->hasTimedOut = false;\n            }\n\n            /* Are we in (WebSocket) shutdown mode? */\n            if (webSocketData->isShuttingDown) {\n                /* Check if we just now drained completely */\n                if (asyncSocket->getBufferedAmount() == 0) {\n                    /* Now perform the actual TCP/TLS shutdown which was postponed due to backpressure */\n                    asyncSocket->shutdown();\n                }\n            } else if (!backpressure || backpressure > asyncSocket->getBufferedAmount()) {\n                /* Only call drain if we actually drained backpressure or if we came here with 0 backpressure */\n                auto *webSocketContextData = (WebSocketContextData<SSL, USERDATA> *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s));\n                if (webSocketContextData->drainHandler) {\n                    webSocketContextData->drainHandler((WebSocket<SSL, isServer, USERDATA> *) s);\n                }\n                /* No need to check for closed here as we leave the handler immediately*/\n            }\n\n            return s;\n        });\n\n        /* Handle FIN, WebSocket does not support half-closed sockets, so simply close */\n        us_socket_context_on_end(SSL, getSocketContext(), [](auto *s) {\n\n            /* If we get a fin, we just close I guess */\n            us_socket_close(SSL, (us_socket_t *) s, (int) ERR_TCP_FIN.length(), (void *) ERR_TCP_FIN.data());\n\n            return s;\n        });\n\n        us_socket_context_on_long_timeout(SSL, getSocketContext(), [](auto *s) {\n            ((WebSocket<SSL, isServer, USERDATA> *) s)->end(1000, \"please reconnect\");\n\n            return s;\n        });\n\n        /* Handle socket timeouts, simply close them so to not confuse client with FIN */\n        us_socket_context_on_timeout(SSL, getSocketContext(), [](auto *s) {\n\n            auto *webSocketData = (WebSocketData *)(us_socket_ext(SSL, s));\n            auto *webSocketContextData = (WebSocketContextData<SSL, USERDATA> *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s));\n\n            if (webSocketContextData->sendPingsAutomatically && !webSocketData->isShuttingDown && !webSocketData->hasTimedOut) {\n                webSocketData->hasTimedOut = true;\n                us_socket_timeout(SSL, s, webSocketContextData->idleTimeoutComponents.second);\n                /* Send ping without being corked */\n                ((AsyncSocket<SSL> *) s)->write(\"\\x89\\x00\", 2);\n                return s;\n            }\n\n            /* Timeout is very simple; we just close it */\n            /* Warning: we happen to know forceClose will not use first parameter so pass nullptr here */\n            forceClose(nullptr, s, ERR_WEBSOCKET_TIMEOUT);\n\n            return s;\n        });\n\n        return this;\n    }\n\n    void free() {\n        WebSocketContextData<SSL, USERDATA> *webSocketContextData = (WebSocketContextData<SSL, USERDATA> *) us_socket_context_ext(SSL, (us_socket_context_t *) this);\n        webSocketContextData->~WebSocketContextData();\n\n        us_socket_context_free(SSL, (us_socket_context_t *) this);\n    }\n\npublic:\n    /* WebSocket contexts are always child contexts to a HTTP context so no SSL options are needed as they are inherited */\n    static WebSocketContext *create(Loop */*loop*/, us_socket_context_t *parentSocketContext, TopicTree<TopicTreeMessage, TopicTreeBigMessage> *topicTree) {\n        WebSocketContext *webSocketContext = (WebSocketContext *) us_create_child_socket_context(SSL, parentSocketContext, sizeof(WebSocketContextData<SSL, USERDATA>));\n        if (!webSocketContext) {\n            return nullptr;\n        }\n\n        /* Init socket context data */\n        new ((WebSocketContextData<SSL, USERDATA> *) us_socket_context_ext(SSL, (us_socket_context_t *)webSocketContext)) WebSocketContextData<SSL, USERDATA>(topicTree);\n        return webSocketContext->init();\n    }\n};\n\n}\n\n#endif // UWS_WEBSOCKETCONTEXT_H\n"
  },
  {
    "path": "src/WebSocketContextData.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2020.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef UWS_WEBSOCKETCONTEXTDATA_H\n#define UWS_WEBSOCKETCONTEXTDATA_H\n\n#include \"Loop.h\"\n#include \"AsyncSocket.h\"\n\n#include \"MoveOnlyFunction.h\"\n#include <string_view>\n#include <vector>\n\n#include \"WebSocketProtocol.h\"\n#include \"TopicTree.h\"\n#include \"WebSocketData.h\"\n\nnamespace uWS {\n\n/* Type queued up when publishing */\nstruct TopicTreeMessage {\n    std::string message;\n    /*OpCode*/ int opCode;\n    bool compress;\n};\nstruct TopicTreeBigMessage {\n    std::string_view message;\n    /*OpCode*/ int opCode;\n    bool compress;\n};\n\ntemplate <bool, bool, typename> struct WebSocket;\n\n/* todo: this looks identical to WebSocketBehavior, why not just std::move that entire thing in? */\n\ntemplate <bool SSL, typename USERDATA>\nstruct WebSocketContextData {\nprivate:\n\npublic:\n\n    /* This one points to the App's shared topicTree */\n    TopicTree<TopicTreeMessage, TopicTreeBigMessage> *topicTree;\n\n    /* The callbacks for this context */\n    MoveOnlyFunction<void(WebSocket<SSL, true, USERDATA> *)> openHandler = nullptr;\n    MoveOnlyFunction<void(WebSocket<SSL, true, USERDATA> *, std::string_view, OpCode)> messageHandler = nullptr;\n    MoveOnlyFunction<void(WebSocket<SSL, true, USERDATA> *, std::string_view, OpCode)> droppedHandler = nullptr;\n    MoveOnlyFunction<void(WebSocket<SSL, true, USERDATA> *)> drainHandler = nullptr;\n    MoveOnlyFunction<void(WebSocket<SSL, true, USERDATA> *, std::string_view, int, int)> subscriptionHandler = nullptr;\n    MoveOnlyFunction<void(WebSocket<SSL, true, USERDATA> *, int, std::string_view)> closeHandler = nullptr;\n    MoveOnlyFunction<void(WebSocket<SSL, true, USERDATA> *, std::string_view)> pingHandler = nullptr;\n    MoveOnlyFunction<void(WebSocket<SSL, true, USERDATA> *, std::string_view)> pongHandler = nullptr;\n\n    /* Settings for this context */\n    size_t maxPayloadLength = 0;\n\n    /* We do need these for async upgrade */\n    CompressOptions compression;\n\n    /* There needs to be a maxBackpressure which will force close everything over that limit */\n    size_t maxBackpressure = 0;\n    bool closeOnBackpressureLimit;\n    bool resetIdleTimeoutOnSend;\n    bool sendPingsAutomatically;\n    unsigned short maxLifetime;\n\n    /* These are calculated on creation */\n    std::pair<unsigned short, unsigned short> idleTimeoutComponents;\n\n    /* This is run once on start-up */\n    void calculateIdleTimeoutCompnents(unsigned short idleTimeout) {\n        unsigned short margin = 4;\n        /* 4, 8 or 16 seconds margin based on idleTimeout */\n        while ((int) idleTimeout - margin * 2 >= margin * 2 && margin < 16) {\n            margin = (unsigned short) (margin << 1);\n        }\n        idleTimeoutComponents = {\n            idleTimeout - (sendPingsAutomatically ? margin : 0), /* reduce normal idleTimeout if it is extended by ping-timeout */\n            margin /* ping-timeout - also used for end() timeout */\n        };\n    }\n\n    ~WebSocketContextData() {\n\n    }\n\n    WebSocketContextData(TopicTree<TopicTreeMessage, TopicTreeBigMessage> *topicTree) : topicTree(topicTree) {\n\n    }\n};\n\n}\n\n#endif // UWS_WEBSOCKETCONTEXTDATA_H\n"
  },
  {
    "path": "src/WebSocketData.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2020.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef UWS_WEBSOCKETDATA_H\n#define UWS_WEBSOCKETDATA_H\n\n#include \"WebSocketProtocol.h\"\n#include \"AsyncSocketData.h\"\n#include \"PerMessageDeflate.h\"\n#include \"TopicTree.h\"\n\n#include <string>\n\nnamespace uWS {\n\nstruct WebSocketData : AsyncSocketData<false>, WebSocketState<true> {\n    /* This guy has a lot of friends - why? */\n    template <bool, bool, typename> friend struct WebSocketContext;\n    template <bool, typename> friend struct WebSocketContextData;\n    template <bool, bool, typename> friend struct WebSocket;\n    template <bool> friend struct HttpContext;\nprivate:\n    std::string fragmentBuffer;\n    unsigned int controlTipLength = 0;\n    bool isShuttingDown = 0;\n    bool hasTimedOut = false;\n    enum CompressionStatus : char {\n        DISABLED,\n        ENABLED,\n        COMPRESSED_FRAME\n    } compressionStatus;\n\n    /* We might have a dedicated compressor */\n    DeflationStream *deflationStream = nullptr;\n    /* And / or a dedicated decompressor */\n    InflationStream *inflationStream = nullptr;\n\n    /* We could be a subscriber */\n    Subscriber *subscriber = nullptr;\npublic:\n    WebSocketData(bool perMessageDeflate, CompressOptions compressOptions, BackPressure &&backpressure) : AsyncSocketData<false>(std::move(backpressure)), WebSocketState<true>() {\n        compressionStatus = perMessageDeflate ? ENABLED : DISABLED;\n\n        /* Initialize the dedicated sliding window(s) */\n        if (perMessageDeflate) {\n            if ((compressOptions & CompressOptions::_COMPRESSOR_MASK) != CompressOptions::SHARED_COMPRESSOR) {\n                deflationStream = new DeflationStream(compressOptions);\n            }\n            if ((compressOptions & CompressOptions::_DECOMPRESSOR_MASK) != CompressOptions::SHARED_DECOMPRESSOR) {\n                inflationStream = new InflationStream(compressOptions);\n            }\n        }\n    }\n\n    ~WebSocketData() {\n        if (deflationStream) {\n            delete deflationStream;\n        }\n\n        if (inflationStream) {\n            delete inflationStream;\n        }\n\n        if (subscriber) {\n            delete subscriber;\n        }\n    }\n};\n\n}\n\n#endif // UWS_WEBSOCKETDATA_H\n"
  },
  {
    "path": "src/WebSocketExtensions.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2021.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef UWS_WEBSOCKETEXTENSIONS_H\n#define UWS_WEBSOCKETEXTENSIONS_H\n\n/* There is a new, huge bug scenario that needs to be fixed:\n * pub/sub does not support being in DEDICATED_COMPRESSOR-mode while having\n * some clients downgraded to SHARED_COMPRESSOR - we cannot allow the client to\n * demand a downgrade to SHARED_COMPRESSOR (yet) until we fix that scenario in pub/sub */\n// #define UWS_ALLOW_SHARED_AND_DEDICATED_COMPRESSOR_MIX\n\n/* We forbid negotiating 8 windowBits since Zlib has a bug with this */\n// #define UWS_ALLOW_8_WINDOW_BITS\n\n#include <climits>\n#include <cctype>\n#include <string>\n#include <string_view>\n#include <tuple>\n\nnamespace uWS {\n\nenum ExtensionTokens {\n    /* Standard permessage-deflate tokens */\n    TOK_PERMESSAGE_DEFLATE = 1838,\n    TOK_SERVER_NO_CONTEXT_TAKEOVER = 2807,\n    TOK_CLIENT_NO_CONTEXT_TAKEOVER = 2783,\n    TOK_SERVER_MAX_WINDOW_BITS = 2372,\n    TOK_CLIENT_MAX_WINDOW_BITS = 2348,\n    /* Non-standard alias for Safari */\n    TOK_X_WEBKIT_DEFLATE_FRAME = 2149,\n    TOK_NO_CONTEXT_TAKEOVER = 2049,\n    TOK_MAX_WINDOW_BITS = 1614\n\n};\n\nstruct ExtensionsParser {\nprivate:\n    int *lastInteger = nullptr;\n\npublic:\n    /* Standard */\n    bool perMessageDeflate = false;\n    bool serverNoContextTakeover = false;\n    bool clientNoContextTakeover = false;\n    int serverMaxWindowBits = 0;\n    int clientMaxWindowBits = 0;\n\n    /* Non-standard Safari */\n    bool xWebKitDeflateFrame = false;\n    bool noContextTakeover = false;\n    int maxWindowBits = 0;\n\n    int getToken(const char *&in, const char *stop) {\n        while (in != stop && !isalnum(*in)) {\n            in++;\n        }\n\n        /* Don't care more than this for now */\n        static_assert(SHRT_MIN > INT_MIN, \"Integer overflow fix is invalid for this platform, report this as a bug!\");\n\n        int hashedToken = 0;\n        while (in != stop && (isalnum(*in) || *in == '-' || *in == '_')) {\n            if (isdigit(*in)) {\n                /* This check is a quick and incorrect fix for integer overflow\n                 * in oss-fuzz but we don't care as it doesn't matter either way */\n                if (hashedToken > SHRT_MIN && hashedToken < SHRT_MAX) {\n                    hashedToken = hashedToken * 10 - (*in - '0');\n                }\n            } else {\n                hashedToken += *in;\n            }\n            in++;\n        }\n        return hashedToken;\n    }\n\n    ExtensionsParser(const char *data, size_t length) {\n        const char *stop = data + length;\n        int token = 1;\n\n        /* Ignore anything before permessage-deflate or x-webkit-deflate-frame */\n        for (; token && token != TOK_PERMESSAGE_DEFLATE && token != TOK_X_WEBKIT_DEFLATE_FRAME; token = getToken(data, stop));\n\n        /* What protocol are we going to use? */\n        perMessageDeflate = (token == TOK_PERMESSAGE_DEFLATE);\n        xWebKitDeflateFrame = (token == TOK_X_WEBKIT_DEFLATE_FRAME);\n\n        while ((token = getToken(data, stop))) {\n            switch (token) {\n            case TOK_X_WEBKIT_DEFLATE_FRAME:\n                /* Duplicates not allowed/supported */\n                return;\n            case TOK_NO_CONTEXT_TAKEOVER:\n                noContextTakeover = true;\n                break;\n            case TOK_MAX_WINDOW_BITS:\n                maxWindowBits = 1;\n                lastInteger = &maxWindowBits;\n                break;\n            case TOK_PERMESSAGE_DEFLATE:\n                /* Duplicates not allowed/supported */\n                return;\n            case TOK_SERVER_NO_CONTEXT_TAKEOVER:\n                serverNoContextTakeover = true;\n                break;\n            case TOK_CLIENT_NO_CONTEXT_TAKEOVER:\n                clientNoContextTakeover = true;\n                break;\n            case TOK_SERVER_MAX_WINDOW_BITS:\n                serverMaxWindowBits = 1;\n                lastInteger = &serverMaxWindowBits;\n                break;\n            case TOK_CLIENT_MAX_WINDOW_BITS:\n                clientMaxWindowBits = 1;\n                lastInteger = &clientMaxWindowBits;\n                break;\n            default:\n                if (token < 0 && lastInteger) {\n                    *lastInteger = -token;\n                }\n                break;\n            }\n        }\n    }\n};\n\n/* Takes what we (the server) wants, returns what we got */\nstatic inline std::tuple<bool, int, int, std::string_view> negotiateCompression(bool wantCompression, int wantedCompressionWindow, int wantedInflationWindow, std::string_view offer) {\n\n    /* If we don't want compression then we are done here */\n    if (!wantCompression) {\n        return {false, 0, 0, \"\"};\n    }\n\n    ExtensionsParser ep(offer.data(), offer.length());\n\n    static thread_local std::string response;\n    response = \"\";\n\n    int compressionWindow = wantedCompressionWindow;\n    int inflationWindow = wantedInflationWindow;\n    bool compression = false;\n\n    if (ep.xWebKitDeflateFrame) {\n        /* We now have compression */\n        compression = true;\n        response = \"x-webkit-deflate-frame\";\n\n        /* If the other peer has DEMANDED us no sliding window,\n         * we cannot compress with anything other than shared compressor */\n        if (ep.noContextTakeover) {\n            /* We must fail here right now (fix pub/sub) */\n#ifndef UWS_ALLOW_SHARED_AND_DEDICATED_COMPRESSOR_MIX\n            if (wantedCompressionWindow != 0) {\n                return {false, 0, 0, \"\"};\n            }\n#endif\n\n            compressionWindow = 0;\n        }\n\n        /* If the other peer has DEMANDED us to use a limited sliding window,\n         * we have to limit out compression sliding window */\n        if (ep.maxWindowBits && ep.maxWindowBits < compressionWindow) {\n            compressionWindow = ep.maxWindowBits;\n#ifndef UWS_ALLOW_8_WINDOW_BITS\n            /* We cannot really deny this, so we have to disable compression in this case */\n            if (compressionWindow == 8) {\n                return {false, 0, 0, \"\"};\n            }\n#endif\n        }\n\n        /* We decide our own inflation sliding window (and their compression sliding window) */\n        if (wantedInflationWindow < 15) {\n            if (!wantedInflationWindow) {\n                response += \"; no_context_takeover\";\n            } else {\n                response += \"; max_window_bits=\" + std::to_string(wantedInflationWindow);\n            }\n        }\n    } else if (ep.perMessageDeflate) {\n        /* We now have compression */\n        compression = true;\n        response = \"permessage-deflate\";\n\n        if (ep.clientNoContextTakeover) {\n            inflationWindow = 0;\n        } else if (ep.clientMaxWindowBits && ep.clientMaxWindowBits != 1) {\n            inflationWindow = std::min<int>(ep.clientMaxWindowBits, inflationWindow);\n        }\n\n        /* Whatever we have now, write */\n        if (inflationWindow < 15) {\n            if (!inflationWindow || !ep.clientMaxWindowBits) {\n                response += \"; client_no_context_takeover\";\n                inflationWindow = 0;\n            } else {\n                response += \"; client_max_window_bits=\" + std::to_string(inflationWindow);\n            }\n        }\n\n        /* This block basically lets the client lower it */\n        if (ep.serverNoContextTakeover) {\n        /* This is an important (temporary) fix since we haven't allowed\n         * these two modes to mix, and pub/sub will not handle this case (yet) */\n#ifdef UWS_ALLOW_SHARED_AND_DEDICATED_COMPRESSOR_MIX\n            compressionWindow = 0;\n#endif\n        } else if (ep.serverMaxWindowBits) {\n            compressionWindow = std::min<int>(ep.serverMaxWindowBits, compressionWindow);\n#ifndef UWS_ALLOW_8_WINDOW_BITS\n            /* Zlib cannot do windowBits=8, memLevel=1 so we raise it up to 9 minimum */\n            if (compressionWindow == 8) {\n                compressionWindow = 9;\n            }\n#endif\n        }\n\n        /* Whatever we have now, write */\n        if (compressionWindow < 15) {\n            if (!compressionWindow) {\n                response += \"; server_no_context_takeover\";\n            } else {\n                response += \"; server_max_window_bits=\" + std::to_string(compressionWindow);\n            }\n        }\n    }\n\n    /* A final sanity check (this check does not actually catch too high values!) */\n    if ((compressionWindow && compressionWindow < 8) || compressionWindow > 15 || (inflationWindow && inflationWindow < 8) || inflationWindow > 15) {\n        return {false, 0, 0, \"\"};\n    }\n\n    return {compression, compressionWindow, inflationWindow, response};\n}\n\n}\n\n#endif // UWS_WEBSOCKETEXTENSIONS_H\n"
  },
  {
    "path": "src/WebSocketHandshake.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2020.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n*/\n\n#ifndef UWS_WEBSOCKETHANDSHAKE_H\n#define UWS_WEBSOCKETHANDSHAKE_H\n\n#include <cstdint>\n#include <cstddef>\n\nnamespace uWS {\n\nstruct WebSocketHandshake {\n    template <int N, typename T>\n    struct static_for {\n        void operator()(uint32_t *a, uint32_t *b) {\n            static_for<N - 1, T>()(a, b);\n            T::template f<N - 1>(a, b);\n        }\n    };\n\n    template <typename T>\n    struct static_for<0, T> {\n        void operator()(uint32_t */*a*/, uint32_t */*hash*/) {}\n    };\n\n    static inline uint32_t rol(uint32_t value, size_t bits) {return (value << bits) | (value >> (32 - bits));}\n    static inline uint32_t blk(uint32_t b[16], size_t i) {\n        return rol(b[(i + 13) & 15] ^ b[(i + 8) & 15] ^ b[(i + 2) & 15] ^ b[i], 1);\n    }\n\n    struct Sha1Loop1 {\n        template <int i>\n        static inline void f(uint32_t *a, uint32_t *b) {\n            a[i % 5] += ((a[(3 + i) % 5] & (a[(2 + i) % 5] ^ a[(1 + i) % 5])) ^ a[(1 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(4 + i) % 5], 5);\n            a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30);\n        }\n    };\n    struct Sha1Loop2 {\n        template <int i>\n        static inline void f(uint32_t *a, uint32_t *b) {\n            b[i] = blk(b, i);\n            a[(1 + i) % 5] += ((a[(4 + i) % 5] & (a[(3 + i) % 5] ^ a[(2 + i) % 5])) ^ a[(2 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(5 + i) % 5], 5);\n            a[(4 + i) % 5] = rol(a[(4 + i) % 5], 30);\n        }\n    };\n    struct Sha1Loop3 {\n        template <int i>\n        static inline void f(uint32_t *a, uint32_t *b) {\n            b[(i + 4) % 16] = blk(b, (i + 4) % 16);\n            a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5);\n            a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30);\n        }\n    };\n    struct Sha1Loop4 {\n        template <int i>\n        static inline void f(uint32_t *a, uint32_t *b) {\n            b[(i + 8) % 16] = blk(b, (i + 8) % 16);\n            a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | (a[(3 + i) % 5] & a[(2 + i) % 5])) + b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5);\n            a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30);\n        }\n    };\n    struct Sha1Loop5 {\n        template <int i>\n        static inline void f(uint32_t *a, uint32_t *b) {\n            b[(i + 12) % 16] = blk(b, (i + 12) % 16);\n            a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5);\n            a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30);\n        }\n    };\n    struct Sha1Loop6 {\n        template <int i>\n        static inline void f(uint32_t *a, uint32_t *b) {\n            b[i] += a[4 - i];\n        }\n    };\n\n    static inline void sha1(uint32_t hash[5], uint32_t b[16]) {\n        uint32_t a[5] = {hash[4], hash[3], hash[2], hash[1], hash[0]};\n        static_for<16, Sha1Loop1>()(a, b);\n        static_for<4, Sha1Loop2>()(a, b);\n        static_for<20, Sha1Loop3>()(a, b);\n        static_for<20, Sha1Loop4>()(a, b);\n        static_for<20, Sha1Loop5>()(a, b);\n        static_for<5, Sha1Loop6>()(a, hash);\n    }\n\n    static inline void base64(unsigned char *src, char *dst) {\n        const char *b64 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n        for (int i = 0; i < 18; i += 3) {\n            *dst++ = b64[(src[i] >> 2) & 63];\n            *dst++ = b64[((src[i] & 3) << 4) | ((src[i + 1] & 240) >> 4)];\n            *dst++ = b64[((src[i + 1] & 15) << 2) | ((src[i + 2] & 192) >> 6)];\n            *dst++ = b64[src[i + 2] & 63];\n        }\n        *dst++ = b64[(src[18] >> 2) & 63];\n        *dst++ = b64[((src[18] & 3) << 4) | ((src[19] & 240) >> 4)];\n        *dst++ = b64[((src[19] & 15) << 2)];\n        *dst++ = '=';\n    }\n\npublic:\n    static inline void generate(const char input[24], char output[28]) {\n        uint32_t b_output[5] = {\n            0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0\n        };\n        uint32_t b_input[16] = {\n            0, 0, 0, 0, 0, 0, 0x32353845, 0x41464135, 0x2d453931, 0x342d3437, 0x44412d39,\n            0x3543412d, 0x43354142, 0x30444338, 0x35423131, 0x80000000\n        };\n\n        for (int i = 0; i < 6; i++) {\n            b_input[i] = (uint32_t) ((input[4 * i + 3] & 0xff) | (input[4 * i + 2] & 0xff) << 8 | (input[4 * i + 1] & 0xff) << 16 | (input[4 * i + 0] & 0xff) << 24);\n        }\n        sha1(b_output, b_input);\n        uint32_t last_b[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 480};\n        sha1(b_output, last_b);\n        for (int i = 0; i < 5; i++) {\n            uint32_t tmp = b_output[i];\n            char *bytes = (char *) &b_output[i];\n            bytes[3] = (char) (tmp & 0xff);\n            bytes[2] = (char) ((tmp >> 8) & 0xff);\n            bytes[1] = (char) ((tmp >> 16) & 0xff);\n            bytes[0] = (char) ((tmp >> 24) & 0xff);\n        }\n        base64((unsigned char *) b_output, output);\n    }\n};\n\n}\n\n#endif // UWS_WEBSOCKETHANDSHAKE_H\n"
  },
  {
    "path": "src/WebSocketProtocol.h",
    "content": "/*\n * Authored by Alex Hultman, 2018-2020.\n * Intellectual property of third-party.\n\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n\n *     http://www.apache.org/licenses/LICENSE-2.0\n\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef UWS_WEBSOCKETPROTOCOL_H\n#define UWS_WEBSOCKETPROTOCOL_H\n\n#include <libusockets.h>\n\n#include <cstdint>\n#include <cstring>\n#include <cstdlib>\n#include <string_view>\n\n#ifdef UWS_USE_SIMDUTF\n  #include <simdutf.h>\n#endif\n\nnamespace uWS {\n\n/* We should not overcomplicate these */\nconstexpr std::string_view ERR_TOO_BIG_MESSAGE(\"Received too big message\");\nconstexpr std::string_view ERR_WEBSOCKET_TIMEOUT(\"WebSocket timed out from inactivity\");\nconstexpr std::string_view ERR_INVALID_TEXT(\"Received invalid UTF-8\");\nconstexpr std::string_view ERR_TOO_BIG_MESSAGE_INFLATION(\"Received too big message, or other inflation error\");\nconstexpr std::string_view ERR_INVALID_CLOSE_PAYLOAD(\"Received invalid close payload\");\nconstexpr std::string_view ERR_PROTOCOL(\"Received invalid WebSocket frame\");\nconstexpr std::string_view ERR_TCP_FIN(\"Received TCP FIN before WebSocket close frame\");\n\nenum OpCode : unsigned char {\n    CONTINUATION = 0,\n    TEXT = 1,\n    BINARY = 2,\n    CLOSE = 8,\n    PING = 9,\n    PONG = 10\n};\n\nenum {\n    CLIENT,\n    SERVER\n};\n\n// 24 bytes perfectly\ntemplate <bool isServer>\nstruct WebSocketState {\npublic:\n    static const unsigned int SHORT_MESSAGE_HEADER = isServer ? 6 : 2;\n    static const unsigned int MEDIUM_MESSAGE_HEADER = isServer ? 8 : 4;\n    static const unsigned int LONG_MESSAGE_HEADER = isServer ? 14 : 10;\n\n    // 16 bytes\n    struct State {\n        unsigned int wantsHead : 1;\n        unsigned int spillLength : 4;\n        signed int opStack : 2; // -1, 0, 1\n        unsigned int lastFin : 1;\n\n        // 15 bytes\n        unsigned char spill[LONG_MESSAGE_HEADER - 1];\n        OpCode opCode[2];\n\n        State() {\n            wantsHead = true;\n            spillLength = 0;\n            opStack = -1;\n            lastFin = true;\n        }\n\n    } state;\n\n    // 8 bytes\n    unsigned int remainingBytes = 0;\n    char mask[isServer ? 4 : 1];\n};\n\nnamespace protocol {\n\ntemplate <typename T>\nT bit_cast(char *c) {\n    T val;\n    memcpy(&val, c, sizeof(T));\n    return val;\n}\n\n/* Byte swap for little-endian systems */\ntemplate <typename T>\nT cond_byte_swap(T value) {\n    static_assert(std::is_trivially_copyable<T>::value, \"T must be trivially copyable\");\n    uint32_t endian_test = 1;\n    if (*reinterpret_cast<char*>(&endian_test)) {\n        uint8_t src[sizeof(T)];\n        uint8_t dst[sizeof(T)];\n\n        std::memcpy(src, &value, sizeof(T));\n        for (size_t i = 0; i < sizeof(T); ++i) {\n            dst[i] = src[sizeof(T) - 1 - i];\n        }\n\n        T result;\n        std::memcpy(&result, dst, sizeof(T));\n        return result;\n    }\n    return value;\n}\n\n#ifdef UWS_USE_SIMDUTF\n\nstatic bool isValidUtf8(unsigned char *s, size_t length)\n{\n    return simdutf::validate_utf8((const char *)s, length);\n}\n\n#else\n// Based on utf8_check.c by Markus Kuhn, 2005\n// https://www.cl.cam.ac.uk/~mgk25/ucs/utf8_check.c\n// Optimized for predominantly 7-bit content by Alex Hultman, 2016\n// Licensed as Zlib, like the rest of this project\n// This runs about 40% faster than simdutf with g++ -mavx\nstatic bool isValidUtf8(unsigned char *s, size_t length)\n{\n    for (unsigned char *e = s + length; s != e; ) {\n        if (s + 16 <= e) {\n            uint64_t tmp[2];\n            memcpy(tmp, s, 16);\n            if (((tmp[0] & 0x8080808080808080) | (tmp[1] & 0x8080808080808080)) == 0) {\n                s += 16;\n                continue;\n            }\n        }\n\n        while (!(*s & 0x80)) {\n            if (++s == e) {\n                return true;\n            }\n        }\n\n        if ((s[0] & 0x60) == 0x40) {\n            if (s + 1 >= e || (s[1] & 0xc0) != 0x80 || (s[0] & 0xfe) == 0xc0) {\n                return false;\n            }\n            s += 2;\n        } else if ((s[0] & 0xf0) == 0xe0) {\n            if (s + 2 >= e || (s[1] & 0xc0) != 0x80 || (s[2] & 0xc0) != 0x80 ||\n                    (s[0] == 0xe0 && (s[1] & 0xe0) == 0x80) || (s[0] == 0xed && (s[1] & 0xe0) == 0xa0)) {\n                return false;\n            }\n            s += 3;\n        } else if ((s[0] & 0xf8) == 0xf0) {\n            if (s + 3 >= e || (s[1] & 0xc0) != 0x80 || (s[2] & 0xc0) != 0x80 || (s[3] & 0xc0) != 0x80 ||\n                    (s[0] == 0xf0 && (s[1] & 0xf0) == 0x80) || (s[0] == 0xf4 && s[1] > 0x8f) || s[0] > 0xf4) {\n                return false;\n            }\n            s += 4;\n        } else {\n            return false;\n        }\n    }\n    return true;\n}\n\n#endif\n\nstruct CloseFrame {\n    uint16_t code;\n    char *message;\n    size_t length;\n};\n\nstatic inline CloseFrame parseClosePayload(char *src, size_t length) {\n    /* If we get no code or message, default to reporting 1005 no status code present */\n    CloseFrame cf = {1005, nullptr, 0};\n    if (length >= 2) {\n        memcpy(&cf.code, src, 2);\n        cf = {cond_byte_swap<uint16_t>(cf.code), src + 2, length - 2};\n        if (cf.code < 1000 || cf.code > 4999 || (cf.code > 1011 && cf.code < 4000) ||\n            (cf.code >= 1004 && cf.code <= 1006) || !isValidUtf8((unsigned char *) cf.message, cf.length)) {\n            /* Even though we got a WebSocket close frame, it in itself is abnormal */\n            return {1006, (char *) ERR_INVALID_CLOSE_PAYLOAD.data(), ERR_INVALID_CLOSE_PAYLOAD.length()};\n        }\n    }\n    return cf;\n}\n\nstatic inline size_t formatClosePayload(char *dst, uint16_t code, const char *message, size_t length) {\n    /* We could have more strict checks here, but never append code 0 or 1005 or 1006 */\n    if (code && code != 1005 && code != 1006) {\n        code = cond_byte_swap<uint16_t>(code);\n        memcpy(dst, &code, 2);\n        /* It is invalid to pass nullptr to memcpy, even though length is 0 */\n        if (message) {\n            memcpy(dst + 2, message, length);\n        }\n        return length + 2;\n    }\n    return 0;\n}\n\nstatic inline size_t messageFrameSize(size_t messageSize) {\n    if (messageSize < 126) {\n        return 2 + messageSize;\n    } else if (messageSize <= UINT16_MAX) {\n        return 4 + messageSize;\n    }\n    return 10 + messageSize;\n}\n\nenum {\n    SND_CONTINUATION = 1,\n    SND_NO_FIN = 2,\n    SND_COMPRESSED = 64\n};\n\ntemplate <bool isServer>\nstatic inline size_t formatMessage(char *dst, const char *src, size_t length, OpCode opCode, size_t reportedLength, bool compressed, bool fin) {\n    size_t messageLength;\n    size_t headerLength;\n    if (reportedLength < 126) {\n        headerLength = 2;\n        dst[1] = (char) reportedLength;\n    } else if (reportedLength <= UINT16_MAX) {\n        headerLength = 4;\n        dst[1] = 126;\n        uint16_t tmp = cond_byte_swap<uint16_t>((uint16_t) reportedLength);\n        memcpy(&dst[2], &tmp, sizeof(uint16_t));\n    } else {\n        headerLength = 10;\n        dst[1] = 127;\n        uint64_t tmp = cond_byte_swap<uint64_t>((uint64_t) reportedLength);\n        memcpy(&dst[2], &tmp, sizeof(uint64_t));\n    }\n\n    dst[0] = (char) ((fin ? 128 : 0) | ((compressed && opCode) ? SND_COMPRESSED : 0) | (char) opCode);\n\n    //printf(\"%d\\n\", (int)dst[0]);\n\n    char mask[4];\n    if (!isServer) {\n        dst[1] |= 0x80;\n        uint32_t random = (uint32_t) rand();\n        memcpy(mask, &random, 4);\n        memcpy(dst + headerLength, &random, 4);\n        headerLength += 4;\n    }\n\n    messageLength = headerLength + length;\n    memcpy(dst + headerLength, src, length);\n\n    if (!isServer) {\n\n        // overwrites up to 3 bytes outside of the given buffer!\n        //WebSocketProtocol<isServer>::unmaskInplace(dst + headerLength, dst + headerLength + length, mask);\n\n        // this is not optimal\n        char *start = dst + headerLength;\n        char *stop = start + length;\n        int i = 0;\n        while (start != stop) {\n            (*start++) ^= mask[i++ % 4];\n        }\n    }\n    return messageLength;\n}\n\n}\n\n// essentially this is only a parser\ntemplate <const bool isServer, typename Impl>\nstruct WebSocketProtocol {\npublic:\n    static const unsigned int SHORT_MESSAGE_HEADER = isServer ? 6 : 2;\n    static const unsigned int MEDIUM_MESSAGE_HEADER = isServer ? 8 : 4;\n    static const unsigned int LONG_MESSAGE_HEADER = isServer ? 14 : 10;\n\nprotected:\n    static inline bool isFin(char *frame) {return *((unsigned char *) frame) & 128;}\n    static inline unsigned char getOpCode(char *frame) {return *((unsigned char *) frame) & 15;}\n    static inline unsigned char payloadLength(char *frame) {return ((unsigned char *) frame)[1] & 127;}\n    static inline bool rsv23(char *frame) {return *((unsigned char *) frame) & 48;}\n    static inline bool rsv1(char *frame) {return *((unsigned char *) frame) & 64;}\n\n    template <int N>\n    static inline void UnrolledXor(char * __restrict data, char * __restrict mask) {\n        if constexpr (N != 1) {\n            UnrolledXor<N - 1>(data, mask);\n        }\n        data[N - 1] ^= mask[(N - 1) % 4];\n    }\n\n    template <int DESTINATION>\n    static inline void unmaskImprecise8(char *src, uint64_t mask, unsigned int length) {\n        for (unsigned int n = (length >> 3) + 1; n; n--) {\n            uint64_t loaded;\n            memcpy(&loaded, src, 8);\n            loaded ^= mask;\n            memcpy(src - DESTINATION, &loaded, 8);\n            src += 8;\n        }\n    }\n\n    /* DESTINATION = 6 makes this not SIMD, DESTINATION = 4 is with SIMD but we don't want that for short messages */\n    template <int DESTINATION>\n    static inline void unmaskImprecise4(char *src, uint32_t mask, unsigned int length) {\n        for (unsigned int n = (length >> 2) + 1; n; n--) {\n            uint32_t loaded;\n            memcpy(&loaded, src, 4);\n            loaded ^= mask;\n            memcpy(src - DESTINATION, &loaded, 4);\n            src += 4;\n        }\n    }\n\n    template <int HEADER_SIZE>\n    static inline void unmaskImpreciseCopyMask(char *src, unsigned int length) {\n        if constexpr (HEADER_SIZE != 6) {\n            char mask[8] = {src[-4], src[-3], src[-2], src[-1], src[-4], src[-3], src[-2], src[-1]};\n            uint64_t maskInt;\n            memcpy(&maskInt, mask, 8);\n            unmaskImprecise8<HEADER_SIZE>(src, maskInt, length);\n        } else {\n            char mask[4] = {src[-4], src[-3], src[-2], src[-1]};\n            uint32_t maskInt;\n            memcpy(&maskInt, mask, 4);\n            unmaskImprecise4<HEADER_SIZE>(src, maskInt, length);\n        }\n    }\n\n    static inline void rotateMask(unsigned int offset, char *mask) {\n        char originalMask[4] = {mask[0], mask[1], mask[2], mask[3]};\n        mask[(0 + offset) % 4] = originalMask[0];\n        mask[(1 + offset) % 4] = originalMask[1];\n        mask[(2 + offset) % 4] = originalMask[2];\n        mask[(3 + offset) % 4] = originalMask[3];\n    }\n\n    static inline void unmaskInplace(char *data, char *stop, char *mask) {\n        while (data < stop) {\n            *(data++) ^= mask[0];\n            *(data++) ^= mask[1];\n            *(data++) ^= mask[2];\n            *(data++) ^= mask[3];\n        }\n    }\n\n    template <unsigned int MESSAGE_HEADER, typename T>\n    static inline bool consumeMessage(T payLength, char *&src, unsigned int &length, WebSocketState<isServer> *wState, void *user) {\n        if (getOpCode(src)) {\n            if (wState->state.opStack == 1 || (!wState->state.lastFin && getOpCode(src) < 2)) {\n                Impl::forceClose(wState, user, ERR_PROTOCOL);\n                return true;\n            }\n            wState->state.opCode[++wState->state.opStack] = (OpCode) getOpCode(src);\n        } else if (wState->state.opStack == -1) {\n            Impl::forceClose(wState, user, ERR_PROTOCOL);\n            return true;\n        }\n        wState->state.lastFin = isFin(src);\n\n        if (Impl::refusePayloadLength(payLength, wState, user)) {\n            Impl::forceClose(wState, user, ERR_TOO_BIG_MESSAGE);\n            return true;\n        }\n\n        if (payLength + MESSAGE_HEADER <= length) {\n            bool fin = isFin(src);\n            if (isServer) {\n                /* This guy can never be assumed to be perfectly aligned since we can get multiple messages in one read */\n                unmaskImpreciseCopyMask<MESSAGE_HEADER>(src + MESSAGE_HEADER, (unsigned int) payLength);\n                if (Impl::handleFragment(src, payLength, 0, wState->state.opCode[wState->state.opStack], fin, wState, user)) {\n                    return true;\n                }\n            } else {\n                if (Impl::handleFragment(src + MESSAGE_HEADER, payLength, 0, wState->state.opCode[wState->state.opStack], isFin(src), wState, user)) {\n                    return true;\n                }\n            }\n\n            if (fin) {\n                wState->state.opStack--;\n            }\n\n            src += payLength + MESSAGE_HEADER;\n            length -= (unsigned int) (payLength + MESSAGE_HEADER);\n            wState->state.spillLength = 0;\n            return false;\n        } else {\n            wState->state.spillLength = 0;\n            wState->state.wantsHead = false;\n            wState->remainingBytes = (unsigned int) (payLength - length + MESSAGE_HEADER);\n            bool fin = isFin(src);\n            if constexpr (isServer) {\n                memcpy(wState->mask, src + MESSAGE_HEADER - 4, 4);\n                uint64_t mask;\n                memcpy(&mask, src + MESSAGE_HEADER - 4, 4);\n                memcpy(((char *)&mask) + 4, src + MESSAGE_HEADER - 4, 4);\n                unmaskImprecise8<0>(src + MESSAGE_HEADER, mask, length);\n                rotateMask(4 - (length - MESSAGE_HEADER) % 4, wState->mask);\n            }\n            Impl::handleFragment(src + MESSAGE_HEADER, length - MESSAGE_HEADER, wState->remainingBytes, wState->state.opCode[wState->state.opStack], fin, wState, user);\n            return true;\n        }\n    }\n\n    /* This one is nicely vectorized on both ARM64 and X64 - especially with -mavx */\n    static inline void unmaskAll(char * __restrict data, char * __restrict mask) {\n        for (int i = 0; i < LIBUS_RECV_BUFFER_LENGTH; i += 16) {\n            UnrolledXor<16>(data + i, mask);\n        }\n    }\n\n    static inline bool consumeContinuation(char *&src, unsigned int &length, WebSocketState<isServer> *wState, void *user) {\n        if (wState->remainingBytes <= length) {\n            if (isServer) {\n                unsigned int n = wState->remainingBytes >> 2;\n                unmaskInplace(src, src + n * 4, wState->mask);\n                for (unsigned int i = 0, s = wState->remainingBytes % 4; i < s; i++) {\n                    src[n * 4 + i] ^= wState->mask[i];\n                }\n            }\n\n            if (Impl::handleFragment(src, wState->remainingBytes, 0, wState->state.opCode[wState->state.opStack], wState->state.lastFin, wState, user)) {\n                return false;\n            }\n\n            if (wState->state.lastFin) {\n                wState->state.opStack--;\n            }\n\n            src += wState->remainingBytes;\n            length -= wState->remainingBytes;\n            wState->state.wantsHead = true;\n            return true;\n        } else {\n            if (isServer) {\n                /* No need to unmask if mask is 0 */\n                uint32_t nullmask = 0;\n                if (memcmp(wState->mask, &nullmask, sizeof(uint32_t))) {\n                    if /*constexpr*/ (LIBUS_RECV_BUFFER_LENGTH == length) {\n                        unmaskAll(src, wState->mask);\n                    } else {\n                        // Slow path\n                        unmaskInplace(src, src + ((length >> 2) + 1) * 4, wState->mask);\n                    }\n                }\n            }\n\n            wState->remainingBytes -= length;\n            if (Impl::handleFragment(src, length, wState->remainingBytes, wState->state.opCode[wState->state.opStack], wState->state.lastFin, wState, user)) {\n                return false;\n            }\n\n            if (isServer && length % 4) {\n                rotateMask(4 - (length % 4), wState->mask);\n            }\n            return false;\n        }\n    }\n\npublic:\n    WebSocketProtocol() {\n\n    }\n\n    static inline void consume(char *src, unsigned int length, WebSocketState<isServer> *wState, void *user) {\n        if (wState->state.spillLength) {\n            src -= wState->state.spillLength;\n            length += wState->state.spillLength;\n            memcpy(src, wState->state.spill, wState->state.spillLength);\n        }\n        if (wState->state.wantsHead) {\n            parseNext:\n            while (length >= SHORT_MESSAGE_HEADER) {\n\n                // invalid reserved bits / invalid opcodes / invalid control frames / set compressed frame\n                if ((rsv1(src) && !Impl::setCompressed(wState, user)) || rsv23(src) || (getOpCode(src) > 2 && getOpCode(src) < 8) ||\n                    getOpCode(src) > 10 || (getOpCode(src) > 2 && (!isFin(src) || payloadLength(src) > 125))) {\n                    Impl::forceClose(wState, user, ERR_PROTOCOL);\n                    return;\n                }\n\n                if (payloadLength(src) < 126) {\n                    if (consumeMessage<SHORT_MESSAGE_HEADER, uint8_t>(payloadLength(src), src, length, wState, user)) {\n                        return;\n                    }\n                } else if (payloadLength(src) == 126) {\n                    if (length < MEDIUM_MESSAGE_HEADER) {\n                        break;\n                    } else if(consumeMessage<MEDIUM_MESSAGE_HEADER, uint16_t>(protocol::cond_byte_swap<uint16_t>(protocol::bit_cast<uint16_t>(src + 2)), src, length, wState, user)) {\n                        return;\n                    }\n                } else if (length < LONG_MESSAGE_HEADER) {\n                    break;\n                } else if (consumeMessage<LONG_MESSAGE_HEADER, uint64_t>(protocol::cond_byte_swap<uint64_t>(protocol::bit_cast<uint64_t>(src + 2)), src, length, wState, user)) {\n                    return;\n                }\n            }\n            if (length) {\n                memcpy(wState->state.spill, src, length);\n                wState->state.spillLength = length & 0xf;\n            }\n        } else if (consumeContinuation(src, length, wState, user)) {\n            goto parseNext;\n        }\n    }\n\n    static const int CONSUME_POST_PADDING = 4;\n    static const int CONSUME_PRE_PADDING = LONG_MESSAGE_HEADER - 1;\n};\n\n}\n\n#endif // UWS_WEBSOCKETPROTOCOL_H\n"
  },
  {
    "path": "tests/BloomFilter.cpp",
    "content": "#include \"../src/BloomFilter.h\"\n\n#include <cassert>\n#include <vector>\n#include <string>\n#include <algorithm>\n#include <iostream>\n\n/* From Wikipedia */\nstd::vector<std::string> commonHeaders = {\n    \"A-IM\",\n    \"Accept\",\n    \"Accept-Charset\",\n    \"Accept-Datetime\",\n    \"Accept-Encoding\",\n    \"Accept-Language\",\n    \"Access-Control-Request-Method\",\n    \"Access-Control-Request-Headers\",\n    \"Authorization\",\n    \"Cache-Control\",\n    \"Connection\",\n    \"Content-Encoding\",\n    \"Content-Length\",\n    \"Content-MD5\",\n    \"Content-Type\",\n    \"Cookie\",\n    \"Date\",\n    \"Expect\",\n    \"Forwarded\",\n    \"From\",\n    \"Host\",\n    \"HTTP2-Settings\",\n    \"If-Match\",\n    \"If-Modified-Since\",\n    \"If-None-Match\",\n    \"If-Range\",\n    \"If-Unmodified-Since\",\n    \"Max-Forwards\",\n    \"Origin\",\n    \"Pragma\",\n    \"Proxy-Authorization\",\n    \"Range\",\n    \"Referer\",\n    \"TE\",\n    \"Trailer\",\n    \"Transfer-Encoding\",\n    \"User-Agent\",\n    \"Upgrade\",\n    \"Via\",\n    \"Warning\",\n\n    /* Put common non-standard ones here */\n};\n\nint main() {\n\n    /* Lowercase everything */\n    std::transform(commonHeaders.begin(), commonHeaders.end(), commonHeaders.begin(), [](std::string &header) {\n        std::transform(header.begin(), header.end(), header.begin(), ::tolower);\n        return header;\n    });\n\n    uWS::BloomFilter bf;\n    unsigned int totalCollisions = 0;\n\n    /* One on one */\n    for (int i = 0; i < commonHeaders.size(); i++) {\n        bf.reset();\n        assert(bf.mightHave(commonHeaders[i]) == false);\n\n        bf.add(commonHeaders[i]);\n        assert(bf.mightHave(commonHeaders[i]) == true);\n\n        for (int j = i + 1; j < commonHeaders.size(); j++) {\n            if (bf.mightHave(commonHeaders[j])) {\n                std::cout << commonHeaders[i] << \" collides with \" << commonHeaders[j] << std::endl;\n                totalCollisions++;\n            }\n        }\n    }\n\n    /* We don't want any direct one-one-one collisions (please) */\n    std::cout << \"Total collisions: \" << totalCollisions << std::endl;\n    assert(totalCollisions == 0);\n\n    unsigned int totalFalsePositives = 0;\n\n    /* Add all except the one we test */\n    for (int i = 0; i < commonHeaders.size(); i++) {\n        bf.reset();\n\n        /* Add all headers but our */\n        for (int j = 0; j < commonHeaders.size(); j++) {\n            if (j != i) {\n                bf.add(commonHeaders[j]);\n            }\n        }\n\n        /* Do we have false positives? */\n        if (bf.mightHave(commonHeaders[i])) {\n            std::cout << commonHeaders[i] << \" has false positives\" << std::endl;\n            totalFalsePositives++;\n        }\n    }\n\n    /* It is totally fine to have a few false positives */\n    std::cout << \"Total false positives: \" << totalFalsePositives << std::endl;\n    assert(totalFalsePositives == 0);\n}\n"
  },
  {
    "path": "tests/ChunkedEncoding.cpp",
    "content": "#include <iostream>\n#include <cassert>\n#include <sstream>\n#include <iomanip>\n#include <vector>\n#include <climits>\n\n#include \"../src/ChunkedEncoding.h\"\n\nvoid consumeChunkEncoding(int maxConsume, std::string_view &chunkEncoded, uint64_t &state) {\n    //int maxConsume = 200;\n\n    if (uWS::isParsingChunkedEncoding(state)) {\n        std::cout << \"already in chunked parsing state!\" << std::endl;\n        std::abort();\n    }\n\n    // this should not break the parser\n    state = uWS::STATE_IS_CHUNKED;\n\n    while (chunkEncoded.length()) {\n\n        /* Split up the chunkEncoded string into further chunks for parsing */\n        std::string_view data = chunkEncoded.substr(0, std::min<size_t>(maxConsume, chunkEncoded.length()));\n        unsigned int data_length_before_parsing = data.length();\n\n        for (auto chunk : uWS::ChunkIterator(&data, &state, true)) {\n        }\n\n        /* Only remove that which was consumed */\n        chunkEncoded.remove_prefix(data_length_before_parsing - data.length());\n\n        if (state == 0) {\n\n            if (chunkEncoded.length() == 0 || chunkEncoded.length() == 74) {\n                break;\n            } else {\n                std::abort();\n            }\n\n            // should be fine\n            state = uWS::STATE_IS_CHUNKED;\n\n            //std::cout << \"remaining chunk:\" << chunkEncoded.length() << std::endl;\n            //std::abort();\n            //break;\n        }\n\n        /* Here we must be in parsingchunked state */\n        if (!uWS::isParsingChunkedEncoding(state)) {\n            std::cout << \"not in parsing chunked strate!\" << std::endl;\n            std::abort();\n        }\n\n    }\n}\n\nvoid runBetterTest(unsigned int maxConsume) {\n    /* A list of chunks */\n    std::vector<std::string_view> chunks = {\n        \"Hello there I am the first segment\",\n        \"Why hello there\",\n        \"\",\n        \"I am last?\",\n        \"And I am a little longer but it doesn't matter\",\n        \"\"\n    };\n\n    /* Encode them in chunked encoding */\n    std::stringstream ss;\n    for (std::string_view chunk : chunks) {\n        /* Generic chunked encoding format */\n        ss << std::hex << chunk.length() << \"\\r\\n\" << chunk << \"\\r\\n\";\n\n        /* Every null chunk is followed by an empty trailer */\n        if (chunk.length() == 0) {\n            ss << \"\\r\\n\";\n        }\n    }\n    std::string buffer = ss.str();\n    std::string_view chunkEncoded = buffer;\n\n    uint64_t state = 0;\n\n    if (uWS::isParsingChunkedEncoding(state)) {\n        std::abort();\n    }\n    consumeChunkEncoding(maxConsume, chunkEncoded, state);\n    if (state != 0) {\n        std::abort();\n    }\n    consumeChunkEncoding(maxConsume, chunkEncoded, state);\n    if (state != 0) {\n        std::abort();\n    }\n\n    // consumeChunkEncoding(chunkEncoded) - consumes in further chunkes and does isParsingChunked checks\n    // assume state == 0 and we still have bytes to parse (we should have consumed EXACTLY right bytes)\n    // consumeChunkEncoding(chunkEncoded)\n    // assume state == 0 and we have no bytes to consume\n}\n\nvoid runTest(unsigned int maxConsume) {\n    /* A list of chunks */\n    std::vector<std::string_view> chunks = {\n        \"Hello there I am the first segment\",\n        \"Why hello there\",\n        \"\",\n        \"I am last?\",\n        \"And I am a little longer but it doesn't matter\",\n        \"\"\n    };\n\n    /* Encode them in chunked encoding */\n    std::stringstream ss;\n    for (std::string_view chunk : chunks) {\n        /* Generic chunked encoding format */\n        ss << std::hex << chunk.length() << \"\\r\\n\" << chunk << \"\\r\\n\";\n\n        /* Every null chunk is followed by an empty trailer */\n        if (chunk.length() == 0) {\n            ss << \"\\r\\n\";\n        }\n    }\n    std::string buffer = ss.str();\n\n    /* Since we have 2 chunked bodies in our buffer, the parser must stop with state == 0 exactly 2 times */\n    unsigned int stoppedWithClearState = 0;\n    \n    /* Begin with a clear state and the full data */\n    uint64_t state = 0;\n    unsigned int chunkOffset = 0;\n    std::string_view chunkEncoded = buffer;\n\n    // consumeChunkEncoding(chunkEncoded) - consumes in further chunkes and does isParsingChunked checks\n    // assume state == 0 and we still have bytes to parse (we should have consumed EXACTLY right bytes)\n    // consumeChunkEncoding(chunkEncoded)\n    // assume state == 0 and we have no bytes to consume\n\n    // this while should be more like if original size or \"is parsing chunked\" (which tests the uWS::wantsChunkedParsing(state))\n    while (chunkEncoded.length()) {\n        /* Parse a small part of the given data */\n        std::string_view data = chunkEncoded.substr(0, std::min<size_t>(maxConsume, chunkEncoded.length()));\n        \n\n        unsigned int data_length_before_parsing = data.length();\n        \n\n        /* Whatever chunk we emit, or part of chunk, it must match the expected one */\n        //std::cout << \"Calling parser now\" << std::endl;\n        for (auto chunk : uWS::ChunkIterator(&data, &state, true)) {\n            std::cout << \"<\" << chunk << \">\" << std::endl;\n\n            /* Run check here */\n            if (!chunk.length() && chunks[chunkOffset].length()) {\n                std::cout << \"We got emitted an empty chunk but expected a non-empty one\" << std::endl;\n                std::abort();\n            }\n\n            if (chunks[chunkOffset].substr(0, chunk.length()) == chunk /*starts_with(chunk)*/) {\n                chunks[chunkOffset].remove_prefix(chunk.length());\n                if (!chunks[chunkOffset].length()) {\n                    chunkOffset++;\n                }\n            } else {\n                std::cerr << \"Chunk does not match! Should be <\" << chunks[chunkOffset] << \">\" << std::endl;\n                std::abort();                \n            }\n        }\n\n        /* The parser returtned, okay count the times it has state == 0, it should be 2 per the whole buffer always */\n        if (state == 0) {\n            printf(\"Parser stopped with no state set!\\n\");\n            stoppedWithClearState++;\n        }\n\n        /* Only remove that which was consumed */\n        chunkEncoded.remove_prefix(data_length_before_parsing - data.length());\n    }\n\n    if (stoppedWithClearState != 2) {\n        std::cerr << \"Error: The parser stopped with no state \" << stoppedWithClearState << \" times!\" << std::endl;\n        std::abort();\n    }\n}\n\nvoid testWithoutTrailer() {\n    /* A list of chunks */\n    std::vector<std::string_view> chunks = {\n        \"Hello there I am the first segment\",\n        \"\"\n    };\n\n    /* Encode them in chunked encoding */\n    std::stringstream ss;\n    for (std::string_view chunk : chunks) {\n        /* Generic chunked encoding format */\n        ss << std::hex << chunk.length() << \"\\r\\n\" << chunk << \"\\r\\n\";\n    }\n    std::string buffer = ss.str();\n    std::string_view dataToConsume(buffer.data(), buffer.length());\n\n    uint64_t state = uWS::STATE_IS_CHUNKED;\n\n    for (auto chunk : uWS::ChunkIterator(&dataToConsume, &state)) {\n\n    }\n\n    if (state) {\n        std::abort();\n    }\n}\n\nint main() {\n\n    testWithoutTrailer();\n\n    for (int i = 1; i < 1000; i++) {\n        runBetterTest(i);\n    }\n\n    for (int i = 1; i < 1000; i++) {\n        runTest(i);\n    }\n\n    std::cout << \"ALL BRUTEFORCE DONE\" << std::endl;\n}"
  },
  {
    "path": "tests/ExtensionsNegotiator.cpp",
    "content": "/* This is a temporary fix since we do not support this mode with pub/sub yet */\n#define UWS_ALLOW_SHARED_AND_DEDICATED_COMPRESSOR_MIX\n\n/* Zlib bug should not affect testing */\n#define UWS_ALLOW_8_WINDOW_BITS\n\n#include \"../src/WebSocketExtensions.h\"\n\n#include <iostream>\n\nvoid testNegotiation(bool wantCompression, int wantedCompressionWindow, int wantedInflationWindow, std::string_view offer,\n                    bool negCompression, int negCompressionWindow, int negInflationWindow, std::string_view negResponse) {\n\n    auto [compression, compressionWindow, inflationWindow, response] = uWS::negotiateCompression(wantCompression, wantedCompressionWindow, wantedInflationWindow, offer);\n\n    if (compression == negCompression && compressionWindow == negCompressionWindow && inflationWindow == negInflationWindow && response == negResponse) {\n        std::cout << \"PASS\" << std::endl;\n    } else {\n        std::cout << \"FAIL: <\" << response << \"> is not expected <\" << negResponse << \">\" << std::endl;\n    }\n\n}\n\nint main() {\n\n    /* Both parties must indicate compression for it to negotiate */\n    testNegotiation(false, 15, 15, \"permessage-deflate\", false, 0, 0, \"\");\n    testNegotiation(false, 15, 15, \"x-webkit-deflate-frame\", false, 0, 0, \"\");\n    testNegotiation(true, 15, 15, \"\", false, 15, 15, \"\");\n    testNegotiation(true, 15, 15, \"\", false, 15, 15, \"\");\n\n    /* client_max_window_bits can only be used if the client indicates support */\n    testNegotiation(true, 15, 11, \"permessage-deflate; \", true, 15, 0, \"permessage-deflate; client_no_context_takeover\");\n    testNegotiation(true, 15, 0, \"permessage-deflate; \", true, 15, 0, \"permessage-deflate; client_no_context_takeover\");\n    testNegotiation(true, 15, 11, \"permessage-deflate; client_max_window_bits=14\", true, 15, 11, \"permessage-deflate; client_max_window_bits=11\");\n    testNegotiation(true, 15, 11, \"permessage-deflate; client_max_window_bits=9\", true, 15, 9, \"permessage-deflate; client_max_window_bits=9\");\n\n    /* server_max_window_bits can always be used */\n    testNegotiation(true, 0, 15, \"permessage-deflate; \", true, 0, 15, \"permessage-deflate; server_no_context_takeover\");\n    testNegotiation(true, 8, 15, \"permessage-deflate; \", true, 8, 15, \"permessage-deflate; server_max_window_bits=8\");\n    testNegotiation(true, 15, 15, \"permessage-deflate; server_max_window_bits=8\", true, 8, 15, \"permessage-deflate; server_max_window_bits=8\");\n    testNegotiation(true, 11, 15, \"permessage-deflate; server_max_window_bits=14\", true, 11, 15, \"permessage-deflate; server_max_window_bits=11\");\n\n    /* x-webkit-deflate-frame has no particular rules */\n    testNegotiation(true, 11, 15, \"x-webkit-deflate-frame; no_context_takeover; max_window_bits=8\", true, 0, 15, \"x-webkit-deflate-frame\");\n    testNegotiation(true, 11, 12, \"x-webkit-deflate-frame; no_context_takeover; max_window_bits=8\", true, 0, 12, \"x-webkit-deflate-frame; max_window_bits=12\");\n    testNegotiation(true, 11, 12, \"x-webkit-deflate-frame; max_window_bits=8\", true, 8, 12, \"x-webkit-deflate-frame; max_window_bits=12\");\n    testNegotiation(true, 15, 0, \"x-webkit-deflate-frame; max_window_bits=15\", true, 15, 0, \"x-webkit-deflate-frame; no_context_takeover\");\n\n    /* Defaults */\n    testNegotiation(true, 15, 15, \"x-webkit-deflate-frame\", true, 15, 15, \"x-webkit-deflate-frame\");\n    testNegotiation(true, 15, 15, \"permessage-deflate\", true, 15, 15, \"permessage-deflate\");\n\n    /* Fail on invalid values */\n    testNegotiation(true, 15, 15, \"x-webkit-deflate-frame; max_window_bits=3\", false, 0, 0, \"\");\n    /* This one doesn't fail, but at least ignores the too high value */\n    testNegotiation(true, 15, 15, \"x-webkit-deflate-frame; max_window_bits=16\", true, 15, 15, \"x-webkit-deflate-frame\");\n\n    testNegotiation(true, 15, 15, \"permessage-deflate; server_max_window_bits=3\", false, 0, 0, \"\");\n    testNegotiation(true, 15, 15, \"permessage-deflate; client_max_window_bits=3\", false, 0, 0, \"\");\n\n    /* Same here; these won't fail but just be ignored */\n    testNegotiation(true, 15, 15, \"permessage-deflate; server_max_window_bits=17\", true, 15, 15, \"permessage-deflate\");\n    testNegotiation(true, 15, 15, \"permessage-deflate; client_max_window_bits=17\", true, 15, 15, \"permessage-deflate\");\n\n    std::cout << \"ALL PASS\" << std::endl;\n}"
  },
  {
    "path": "tests/HttpParser.cpp",
    "content": "#include <iostream>\n#include <cassert>\n\n#include \"../src/HttpParser.h\"\n\nint main() {\n    /* Parser needs at least 8 bytes post padding */\n    unsigned char data[] = {0x47, 0x45, 0x54, 0x20, 0x2f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0xd, 0xa, 0x61, 0x73, 0x63, 0x69, 0x69, 0x3a, 0x20, 0x74, 0x65, 0x73, 0x74, 0xd, 0xa, 0x75, 0x74, 0x66, 0x38, 0x3a, 0x20, 0xd1, 0x82, 0xd0, 0xb5, 0xd1, 0x81, 0xd1, 0x82, 0xd, 0xa, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0xd, 0xa, 0xd, 0xa, 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E'};\n    int size = sizeof(data) - 8;\n    void *user = nullptr;\n    void *reserved = nullptr;\n\n    uWS::HttpParser httpParser;\n\n    auto [err, returnedUser] = httpParser.consumePostPadded((char *) data, size, user, reserved, [reserved](void *s, uWS::HttpRequest *httpRequest) -> void * {\n\n        std::cout << httpRequest->getMethod() << std::endl;\n\n        for (auto [key, value] : *httpRequest) {\n            std::cout << key << \": \" << value << std::endl;\n        }\n\n        /* Since we did proper whitespace trimming this thing is there, but empty */\n        assert(httpRequest->getHeader(\"utf8\").data());\n\n        /* Return ok */\n        return s;\n\n    }, [](void *user, std::string_view data, bool fin) -> void * {\n\n        /* Return ok */\n        return user;\n\n    });\n\n    std::cout << \"HTTP DONE\" << std::endl;\n\n}"
  },
  {
    "path": "tests/HttpRouter.cpp",
    "content": "#include \"../src/HttpRouter.h\"\n\n#include <cassert>\n#include <iostream>\n\nvoid testMethodPriority() {\n    std::cout << \"TestMethodPriority\" << std::endl;\n    uWS::HttpRouter<int> r;\n    std::string result;\n\n    r.add({\"*\"}, \"/static/route\", [&result](auto *) {\n        std::cout << \"ANY static route\" << std::endl;\n        result += \"AS\";\n        return true;\n    }, r.LOW_PRIORITY);\n\n    r.add({\"PATCH\"}, \"/static/route\", [&result](auto *) {\n        std::cout << \"PATCH static route\" << std::endl;\n        result += \"PS\";\n        return false;\n    });\n\n    r.add({\"GET\"}, \"/static/route\", [&result](auto *) {\n        std::cout << \"GET static route\" << std::endl;\n        result += \"GS\";\n        return true;\n    });\n\n    assert(r.route(\"nonsense\", \"/static/route\") == true);\n    assert(r.route(\"GET\", \"/static\") == false);\n    assert(result == \"AS\");\n\n    /* Should end up directly in ANY handler */\n    result.clear();\n    assert(r.route(\"POST\", \"/static/route\"));\n    assert(result == \"AS\");\n\n    /* Should up directly in GET handler */\n    result.clear();\n    assert(r.route(\"GET\", \"/static/route\"));\n    assert(result == \"GS\");\n\n    /* Should end up in PATCH then in ANY handler */\n    result.clear();\n    assert(r.route(\"PATCH\", \"/static/route\"));\n    assert(result == \"PSAS\");\n}\n\nvoid testDeepParameterRoutes() {\n    std::cout << \"TestDeepParameterRoutes\" << std::endl;\n    uWS::HttpRouter<int> r;\n    std::string result;\n\n    r.add({\"GET\"}, \"/something/:id/sync\", [&result](auto *h) {\n        result += \"ETT\";\n        return false;\n    });\n\n    r.add({\"GET\"}, \"/something/:somethingId/pin\", [&result](auto *h) {\n        result += \"TVÅ\";\n        return false;\n    });\n\n    r.add({\"GET\"}, \"/something/:id/:attribute\", [&result](auto *h) {\n        result += \"TRE\";\n        return false;\n    });\n\n    assert(r.route(\"GET\", \"/something/1234/pin\") == false);\n    assert(result == \"TVÅTRE\");\n\n    result.clear();\n    assert(r.route(\"GET\", \"/something/1234/sync\") == false);\n    assert(result == \"ETTTRE\");\n}\n\nvoid testPatternPriority() {\n    std::cout << \"TestPatternPriority\" << std::endl;\n    uWS::HttpRouter<int> r;\n    std::string result;\n\n    r.add({\"*\"}, \"/a/b/c\", [&result](auto *) {\n        std::cout << \"ANY static route\" << std::endl;\n        result += \"AS\";\n        return false;\n    }, r.LOW_PRIORITY);\n\n    r.add({\"GET\"}, \"/a/:b/c\", [&result](auto *) {\n        std::cout << \"GET parameter route\" << std::endl;\n        result += \"GP\";\n        return false;\n    });\n\n    r.add({\"GET\"}, \"/a/*\", [&result](auto *) {\n        std::cout << \"GET wildcard route\" << std::endl;\n        result += \"GW\";\n        return false;\n    });\n\n    r.add({\"GET\"}, \"/a/b/c\", [&result](auto *) {\n        std::cout << \"GET static route\" << std::endl;\n        result += \"GS\";\n        return false;\n    });\n\n    r.add({\"POST\"}, \"/a/:b/c\", [&result](auto *) {\n        std::cout << \"POST parameter route\" << std::endl;\n        result += \"PP\";\n        return false;\n    });\n\n    r.add({\"*\"}, \"/a/:b/c\", [&result](auto *) {\n        std::cout << \"ANY parameter route\" << std::endl;\n        result += \"AP\";\n        return false;\n    }, r.LOW_PRIORITY);\n\n    assert(r.route(\"POST\", \"/a/b/c\") == false);\n    assert(result == \"PPASAP\");\n\n    result.clear();\n    assert(r.route(\"GET\", \"/a/b/c\") == false);\n    assert(result == \"GSGPGWASAP\");\n}\n\nvoid testUpgrade() {\n    std::cout << \"TestUpgrade\" << std::endl;\n    uWS::HttpRouter<int> r;\n    std::string result;\n\n    /* HTTP on / */\n    r.add({\"GET\"}, \"/something\", [&result](auto *) {\n        result += \"GS\";\n        return true;\n    }, r.MEDIUM_PRIORITY);\n\n    /* HTTP on /* */\n    r.add({\"GET\"}, \"/*\", [&result](auto *) {\n        result += \"GW\";\n        return false;\n    }, r.MEDIUM_PRIORITY);\n\n    /* WebSockets on /* */\n    r.add({\"GET\"}, \"/*\", [&result](auto *) {\n        result += \"WW\";\n        return false;\n    }, r.HIGH_PRIORITY);\n\n    assert(r.route(\"GET\", \"/something\"));\n    assert(result == \"WWGS\");\n    result.clear();\n\n    assert(r.route(\"GET\", \"/\") == false);\n    assert(result == \"WWGW\");\n}\n\nvoid testBugReports() {\n    std::cout << \"TestBugReports\" << std::endl;\n    {\n        uWS::HttpRouter<int> r;\n        std::string result;\n\n        r.add({\"GET\"}, \"/route\", [&result](auto *) {\n            result += \"ROUTE\";\n            return true;\n        }, r.MEDIUM_PRIORITY);\n\n        r.add({\"GET\"}, \"/route/:id\", [&result](auto *) {\n            result += \"ROUID\";\n            return true;\n        }, r.MEDIUM_PRIORITY);\n\n        r.route(\"GET\", \"/route/21\");\n        assert(result == \"ROUID\");\n\n        result = \"\";\n        r.route(\"GET\", \"/route\");\n        assert(result == \"ROUTE\");\n\n        result = \"\";\n        r.remove(\"GET\", \"/route\", r.MEDIUM_PRIORITY);\n        r.route(\"GET\", \"/route\");\n        assert(result == \"\");\n\n        std::cout << \"TRYING TO DELETE /route/:id\" << std::endl;\n        bool found = r.remove(\"GET\", \"/route/:id\", r.MEDIUM_PRIORITY);\n        std::cout << \"Found:\" << found << std::endl;\n\n        /* The bug is really only this line, it does not remove parameter routes */\n        r.route(\"GET\", \"/route/21\");\n        std::cout << \"Found:\" << found << \", \" << result << std::endl;\n        assert(result == \"\");\n    }\n    {\n        uWS::HttpRouter<int> r;\n        std::string result;\n\n        r.add({\"GET\"}, \"/foo//////bar/baz/qux\", [&result](auto *) {\n            result += \"MANYSLASH\";\n            return false;\n        }, r.MEDIUM_PRIORITY);\n\n        r.add({\"GET\"}, \"/foo\", [&result](auto *) {\n            result += \"FOO\";\n            return false;\n        }, r.MEDIUM_PRIORITY);\n\n        r.route(\"GET\", \"/foo\");\n        r.route(\"GET\", \"/foo/\");\n        r.route(\"GET\", \"/foo//bar/baz/qux\");\n        r.route(\"GET\", \"/foo//////bar/baz/qux\");\n        assert(result == \"FOOMANYSLASH\");\n    }\n\n    {\n        uWS::HttpRouter<int> r;\n        std::string result;\n\n        r.add({\"GET\"}, \"/test/*\", [&result](auto *) {\n            result += \"TEST\";\n            return false;\n        }, r.MEDIUM_PRIORITY);\n\n        r.route(\"GET\", \"/test/\");\n        assert(result == \"TEST\");\n    }\n\n    {\n        uWS::HttpRouter<int> r;\n        std::string result;\n\n        /* WS on /* */\n        r.add({\"GET\"}, \"/*\", [&result](auto *) {\n            result += \"WW\";\n            return false;\n        }, r.HIGH_PRIORITY);\n\n        /* HTTP on /ok */\n        r.add({\"GET\"}, \"/ok\", [&result](auto *) {\n            result += \"GS\";\n            return false;\n        }, r.MEDIUM_PRIORITY);\n\n        r.add({\"GET\"}, \"/*\", [&result](auto *) {\n            result += \"GW\";\n            return false;\n        }, r.MEDIUM_PRIORITY);\n\n        r.route(\"GET\", \"/ok\");\n        assert(result == \"WWGSGW\");\n    }\n\n    {\n        uWS::HttpRouter<int> r;\n        std::string result;\n\n        /* WS on / */\n        r.add({\"GET\"}, \"/\", [&result](auto *) {\n            result += \"WS\";\n            return false;\n        }, r.HIGH_PRIORITY);\n\n        /* HTTP on / */\n        r.add({\"GET\"}, \"/\", [&result](auto *) {\n            result += \"GS\";\n            return false;\n        }, r.MEDIUM_PRIORITY);\n\n        r.route(\"GET\", \"/\");\n        assert(result == \"WSGS\");\n    }\n\n    {\n        uWS::HttpRouter<int> r;\n        std::string result;\n\n        /* WS on /* */\n        r.add({\"GET\"}, \"/*\", [&result](auto *) {\n            result += \"WW\";\n            return false;\n        }, r.HIGH_PRIORITY);\n\n        /* GET on /static */\n        r.add({\"GET\"}, \"/static\", [&result](auto *) {\n            result += \"GSL\";\n            return false;\n        }, r.MEDIUM_PRIORITY);\n\n        /* ANY on /* */\n        r.add({\"*\"}, \"/*\", [&result](auto *) {\n            result += \"AW\";\n            return false;\n        }, r.LOW_PRIORITY);\n\n        r.route(\"GET\", \"/static\");\n        assert(result == \"WWGSLAW\");\n    }\n\n    {\n        uWS::HttpRouter<int> r;\n        std::string result;\n\n        /* WS on /* */\n        r.add({\"GET\"}, \"/*\", [&result](auto *) {\n            result += \"WW\";\n            return false;\n        }, r.HIGH_PRIORITY);\n\n        /* GET on / */\n        r.add({\"GET\"}, \"/\", [&result](auto *) {\n            result += \"GSS\";\n            return false;\n        }, r.MEDIUM_PRIORITY);\n\n        /* GET on /static */\n        r.add({\"GET\"}, \"/static\", [&result](auto *) {\n            result += \"GSL\";\n            return false;\n        }, r.MEDIUM_PRIORITY);\n\n        /* ANY on /* */\n        r.add({\"*\"}, \"/*\", [&result](auto *) {\n            result += \"AW\";\n            return false;\n        }, r.LOW_PRIORITY);\n\n        r.route(\"GET\", \"/static\");\n        assert(result == \"WWGSLAW\");\n    }\n\n    {\n        uWS::HttpRouter<int> r;\n        std::string result;\n\n        r.add({\"GET\"}, \"/foo\", [&result](auto *) {\n            result += \"FOO\";\n            return false;\n        }, r.MEDIUM_PRIORITY);\n\n        r.add({\"GET\"}, \"/:id\", [&result](auto *) {\n            result += \"ID\";\n            return false;\n        }, r.MEDIUM_PRIORITY);\n\n        r.add({\"GET\"}, \"/1ab\", [&result](auto *) {\n            result += \"ONEAB\";\n            return false;\n        }, r.MEDIUM_PRIORITY);\n\n        r.route(\"GET\", \"/1ab\");\n        // this one fails with IDONEAB\n        std::cout << result << std::endl;\n        assert(result == \"ONEABID\");\n    }\n\n    {\n        uWS::HttpRouter<int> r;\n        std::string result;\n\n        r.add({\"GET\"}, \"/*\", [&result](auto *) {\n            result += \"STAR\";\n            return false;\n        }, r.MEDIUM_PRIORITY);\n\n        r.add({\"GET\"}, \"/\", [&result](auto *) {\n            result += \"STATIC\";\n            return false;\n        }, r.MEDIUM_PRIORITY);\n\n        r.route(\"GET\", \"/\");\n        std::cout << result << std::endl;\n        // this one fails with STARSTATIC\n        assert(result == \"STATICSTAR\");\n    }\n\n}\n\nvoid testParameters() {\n    std::cout << \"TestParameters\" << std::endl;\n    uWS::HttpRouter<int> r;\n    std::string result;\n\n    r.add({\"GET\"}, \"/candy/:kind/*\", [&result](auto *h) {\n        auto [paramsTop, params] = h->getParameters();\n\n        assert(paramsTop == 0);\n        assert(params[0] == \"lollipop\");\n\n        result += \"GPW\";\n        return false;\n    });\n\n    r.add({\"GET\"}, \"/candy/lollipop/*\", [&result](auto *h) {\n        auto [paramsTop, params] = h->getParameters();\n\n        assert(paramsTop == -1);\n\n        result += \"GLW\";\n        return false;\n    });\n\n    r.add({\"GET\"}, \"/candy/:kind/:action\", [&result](auto *h) {\n        auto [paramsTop, params] = h->getParameters();\n\n        assert(paramsTop == 1);\n        assert(params[0] == \"lollipop\");\n        assert(params[1] == \"eat\");\n\n        result += \"GPP\";\n        return false;\n    });\n\n    r.add({\"GET\"}, \"/candy/lollipop/:action\", [&result](auto *h) {\n        auto [paramsTop, params] = h->getParameters();\n\n        assert(params[0] == \"eat\");\n        assert(paramsTop == 0);\n\n        result += \"GLP\";\n        return false;\n    });\n\n    r.add({\"GET\"}, \"/candy/lollipop/eat\", [&result](auto *h) {\n        auto [paramsTop, params] = h->getParameters();\n\n        assert(paramsTop == -1);\n\n        result += \"GLS\";\n        return false;\n    });\n\n    r.route(\"GET\", \"/candy/lollipop/eat\");\n    assert(result == \"GLSGLPGLWGPPGPW\");\n    result.clear();\n\n    r.route(\"GET\", \"/candy/lollipop/\");\n    r.route(\"GET\", \"/candy/lollipop\");\n    r.route(\"GET\", \"/candy/\");\n    assert(result == \"GLWGPW\");\n}\n\n#include <chrono>\n\nvoid testPerformance() {\n    std::cout << \"TestPerformance\" << std::endl;\n    uWS::HttpRouter<int> r;\n\n    r.add({\"GET\"}, \"/*\", [](auto *h) {\n        return true;\n    });\n\n    r.add({\"*\"}, \"/*\", [](auto *h) {\n        return true;\n    });\n\n    auto start = std::chrono::steady_clock::now();\n    for (int i = 0; i < 1000000; i++) {\n        r.route(\"GET\", \"/something\");\n        r.route(\"other\", \"/whatever\");\n    }\n    auto end = std::chrono::steady_clock::now();\n\n    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();\n    std::cout << \"Duration: \" << duration << \"ms\" << std::endl;\n}\n\nint main() {\n    testDeepParameterRoutes();\n    testPatternPriority();\n    testMethodPriority();\n    testUpgrade();\n    testBugReports();\n    testParameters();\n    testPerformance();\n}\n"
  },
  {
    "path": "tests/Makefile",
    "content": "default:\n\t$(CXX) -std=c++17 -fsanitize=address Query.cpp -o Query\n\t./Query\n\t$(CXX) -std=c++17 -fsanitize=address ChunkedEncoding.cpp -o ChunkedEncoding\n\t./ChunkedEncoding\n\t$(CXX) -std=c++17 -fsanitize=address TopicTree.cpp -o TopicTree\n\t./TopicTree\n\t$(CXX) -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG -std=c++17 -g -fsanitize=address HttpRouter.cpp -o HttpRouter\n\t./HttpRouter\n\t$(CXX) -std=c++17 -fsanitize=address BloomFilter.cpp -o BloomFilter\n\t./BloomFilter\n\t$(CXX) -std=c++17 -fsanitize=address ExtensionsNegotiator.cpp -o ExtensionsNegotiator\n\t./ExtensionsNegotiator\n\t$(CXX) -std=c++17 -fsanitize=address HttpParser.cpp -o HttpParser\n\t./HttpParser\n\nperformance:\n\t$(CXX) -std=c++17 HttpRouter.cpp -O3 -o HttpRouter\n\t./HttpRouter\n\nsmoke:\n\t../Crc32 &\n\tsleep 1\n\t~/.deno/bin/deno run --allow-net smoke.mjs\n\tnode smoke.mjs\n\tpkill Crc32\n\ncompliance:\n\t../EchoBody &\n\tsleep 1\n\t~/.deno/bin/deno run --allow-net ../h1spec/http_test.ts localhost 3000\n\tpkill EchoBody\n"
  },
  {
    "path": "tests/Query.cpp",
    "content": "#include <iostream>\n#include <cassert>\n\n#include \"../src/QueryParser.h\"\n\nint main() {\n\n    {\n        std::string buf = \"?test1=&test2=someValue\";\n        assert(uWS::getDecodedQueryValue(\"test2\", (char *) buf.data()) == \"someValue\");\n    }\n\n    {\n        std::string buf = \"?test1=&test2=someValue\";\n        assert(uWS::getDecodedQueryValue(\"test1\", (char *) buf.data()) == \"\");\n        assert(uWS::getDecodedQueryValue(\"test2\", (char *) buf.data()) == \"someValue\");\n    }\n\n    {\n        std::string buf = \"?Kest1=&test2=someValue\";\n        assert(uWS::getDecodedQueryValue(\"test2\", (char *) buf.data()) == \"someValue\");\n    }\n\n    {\n        std::string buf = \"?Test1=&Kest2=some\";\n        assert(uWS::getDecodedQueryValue(\"Test1\", (char *) buf.data()) == \"\");\n        assert(uWS::getDecodedQueryValue(\"Kest2\", (char *) buf.data()) == \"some\");\n    }\n\n    {\n        std::string buf = \"?Test1=&Kest2=some\";\n        assert(uWS::getDecodedQueryValue(\"Test1\", (char *) buf.data()).data() != nullptr);\n        assert(uWS::getDecodedQueryValue(\"sdfsdf\", (char *) buf.data()).data() == nullptr);\n    }\n\n    {\n        std::string buf = \"?Kest1=&test2=some%20Value\";\n        assert(uWS::getDecodedQueryValue(\"test2\", (char *) buf.data()) == \"some Value\");\n    }\n\n    return 0;\n}"
  },
  {
    "path": "tests/README.md",
    "content": "# Testing\nThis folder holds some unit tests and a smoke test. These are run by GitHub Actions on every push. There are more tests in fuzzing, benchmarks folders and elsewhere.\n\n* We test with 500+ **standards conformance tests** known as the Autobahn|Testsuite where we get a full perfect score.\n* In the fuzzing folder you will find extensive **security fuzz testing** under AddressSanitizer, MemoySanitizer, UndefinedBehaviorSanitizer executed by Google on a daily basis. We also fuzz a short while as part of GitHub Actions.\n* HTTP standards conformance tests are run on every commit, testing fragmentation, invalid chars, and the like.\n* In benchmarks folder you can find **performance testing** - we've done extensive performance testing of every commit since before we even had a single line of code.\n* A set of **integration smoke tests** for testing basic features against real-world \"web browsers\" (Deno, Node.js and Bun are the \"web browsers\").\n* And of course in this folder you can find the very **module unit tests** that check individual modules.\n* Customers and users indirectly feed us with **real world, high scale production testing**.\n* Semmle perform **static code analysis** and security testing for us, where we get the perfect A+ score.\n"
  },
  {
    "path": "tests/TopicTree.cpp",
    "content": "#include \"../src/TopicTree.h\"\n\n#include <cassert>\n#include <iostream>\n\n/* Modifying the topicTree inside callback is not allowed, we had\n * tests for this before but we never need this to work anyways.\n * Closing a socket when reaching too much backpressure is done\n * deferred to next event loop iteration so we never need to modify\n * topicTree inside callback - removed this test */\n\n/* This tests pretty much all features for obvious incorrectness */\nvoid testCorrectness() {\n    std::cout << \"TestCorrectness\" << std::endl;\n\n    uWS::TopicTree<std::string, std::string_view> *topicTree;\n    std::map<void *, std::string> expectedResult;\n    std::map<void *, std::string> actualResult;\n\n    topicTree = new uWS::TopicTree<std::string, std::string_view>([&topicTree, &actualResult](uWS::Subscriber *s, std::string &message, auto flags) {\n\n        actualResult[s] += message;\n\n        /* Success */\n        return false;\n    });\n\n    uWS::Subscriber *s1 = topicTree->createSubscriber();\n    uWS::Subscriber *s2 = topicTree->createSubscriber();\n\n    /* Make sure s1 < s2 (for debugging) */\n    if (s2 < s1) {\n        uWS::Subscriber *tmp = s1;\n        s1 = s2;\n        s2 = tmp;\n    }\n\n    /* Publish to topic3 - nobody should see this */\n    topicTree->publish(nullptr, \"topic3\", \"Nobody should see\");\n\n    /* Subscribe s1 to topic3 - s1 should not see above message */\n    topicTree->subscribe(s1, \"topic3\");\n\n    /* Publish to topic3 with s1 as sender - s1 should not get its own messages */\n    topicTree->publish(s1, \"topic3\", \"Nobody should see\");\n\n    /* Subscribe s2 to topic3 - should not get any message */\n    topicTree->subscribe(s2, \"topic3\");\n\n    /* Publish to topic3 without sender - both should see */\n    topicTree->publish(nullptr, \"topic3\", \"Both should see\");\n\n    /* Publish to topic3 with s2 as sender - s1 should see */\n    topicTree->publish(s2, \"topic3\", \"s1 should see, not s2\");\n\n    /* Publish to topic3 with s1 as sender - s2 should see */\n    topicTree->publish(s1, \"topic3\", \"s2 should see, not s1\");\n\n    /* Publish to topic3 without sender - both should see */\n    topicTree->publish(nullptr, \"topic3\", \"Again, both should see this as well\");\n\n    // todo: add more cases involving more topics and duplicates, etc\n\n    /* Fill out expectedResult */\n    expectedResult = {\n        {s1, \"Both should sees1 should see, not s2Again, both should see this as well\"},\n        {s2, \"Both should sees2 should see, not s1Again, both should see this as well\"}\n    };\n\n    /* Compare result with expected result for every subscriber */\n    topicTree->drain();\n    for (auto &p : expectedResult) {\n        std::cout << \"Subscriber: \" << p.first << std::endl;\n\n        if (p.second != actualResult[p.first]) {\n            std::cout << \"ERROR: <\" << actualResult[p.first] << \"> should be <\" << p.second << \">\" << std::endl;\n            exit(1);\n        }\n    }\n\n    /* Release resources */\n    topicTree->freeSubscriber(s1);\n    topicTree->freeSubscriber(s2);\n\n    delete topicTree;\n}\n\nvoid testBugReport() {\n    std::cout << \"TestBugReport\" << std::endl;\n\n    uWS::TopicTree<std::string, std::string_view> *topicTree;\n    std::map<void *, std::string> expectedResult;\n    std::map<void *, std::string> actualResult;\n\n    topicTree = new uWS::TopicTree<std::string, std::string_view>([&topicTree, &actualResult](uWS::Subscriber *s, std::string &message, auto flags) {\n\n        actualResult[s] += message;\n\n        /* Success */\n        return false;\n    });\n\n    uWS::Subscriber *s1 = topicTree->createSubscriber();\n    uWS::Subscriber *s2 = topicTree->createSubscriber();\n\n    /* Make sure s1 < s2 (for debugging) */\n    if (s2 < s1) {\n        uWS::Subscriber *tmp = s1;\n        s1 = s2;\n        s2 = tmp;\n    }\n\n    /* Each subscriber to its own topic */\n    topicTree->subscribe(s1, \"b1\");\n    topicTree->subscribe(s2, \"b2\");\n\n    /* This one should send b2 to s2 */\n    topicTree->publish(s1, \"b1\", \"b1\");\n    topicTree->publish(s1, \"b2\", \"b2\");\n\n    /* This one should send b1 to s1 */\n    topicTree->publish(s2, \"b1\", \"b1\");\n    topicTree->publish(s2, \"b2\", \"b2\");\n\n    /* Fill out expectedResult */\n    expectedResult = {\n        {s1, \"b1\"},\n        {s2, \"b2\"}\n    };\n\n    /* Compare result with expected result for every subscriber */\n    topicTree->drain();\n    for (auto &p : expectedResult) {\n        std::cout << \"Subscriber: \" << p.first << std::endl;\n\n        if (p.second != actualResult[p.first]) {\n            std::cout << \"ERROR: <\" << actualResult[p.first] << \"> should be <\" << p.second << \">\" << std::endl;\n            exit(1);\n        }\n    }\n\n    /* Release resources */\n    topicTree->freeSubscriber(s1);\n    topicTree->freeSubscriber(s2);\n\n    delete topicTree;\n}\n\nvoid testReorderingv19() {\n    std::cout << \"TestReorderingv19\" << std::endl;\n\n    uWS::TopicTree<std::string, std::string_view> *topicTree;\n    std::map<void *, std::string> expectedResult;\n    std::map<void *, std::string> actualResult;\n\n    topicTree = new uWS::TopicTree<std::string, std::string_view>([&topicTree, &actualResult](uWS::Subscriber *s, std::string &message, auto flags) {\n\n        actualResult[s] += message;\n\n        /* Success */\n        return false;\n    });\n\n    uWS::Subscriber *s1 = topicTree->createSubscriber();\n\n    /* Subscribe to 100 topics */\n    for (int i = 0; i < 100; i++) {\n        topicTree->subscribe(s1, std::to_string(i));\n    }\n\n    /* Publish to 100 topics in order with messages in order */\n    for (int i = 0; i < 100; i++) {\n        topicTree->publish(nullptr, std::to_string(i), std::to_string(i) + \",\");\n\n        expectedResult[s1].append(std::to_string(i) + \",\");\n    }\n\n    /* Compare result with expected result for every subscriber */\n    topicTree->drain();\n    for (auto &p : expectedResult) {\n        std::cout << \"Subscriber: \" << p.first << std::endl;\n\n        if (p.second != actualResult[p.first]) {\n            std::cout << \"ERROR: <\" << actualResult[p.first] << \"> should be <\" << p.second << \">\" << std::endl;\n            exit(1);\n        }\n    }\n\n    /* Release resources */\n    topicTree->freeSubscriber(s1);\n\n    delete topicTree;\n}\n\nint main() {\n    testCorrectness();\n    testBugReport();\n    testReorderingv19();\n}"
  },
  {
    "path": "tests/smoke.mjs",
    "content": "/* This smoke test runs against the Crc32 example program for now, but this example will be extended for more tests */\n\nvar crc32 = (function () {\n    var table = new Uint32Array(256);\n    for (var i = 256; i--;) {\n        var tmp = i;\n        for (var k = 8; k--;) {\n            tmp = tmp & 1 ? 3988292384 ^ tmp >>> 1 : tmp >>> 1;\n        }\n        table[i] = tmp;\n    }\n    return function (data) {\n        var crc = -1; // Begin with all bits set ( 0xffffffff )\n        for (var i = 0, l = data.length; i < l; i++) {\n            crc = crc >>> 8 ^ table[crc & 255 ^ data[i]];\n        }\n        return (crc ^ -1) >>> 0; // Apply binary NOT\n    };\n})();\n\nasync function chunkedCrc32Test(array) {\n\n    console.log(\"Making chunked request with body size: \" + array.length);\n\n    const stream = new ReadableStream(/*{type: \"bytes\"}, */{\n        async start(controller) {\n            await 1;\n            controller.enqueue(array);\n            controller.close();\n        },\n    });\n\n    const r = await fetch(\"http://localhost:3000\", {\n        method: 'POST',\n        headers: { 'Content-Type': 'application/octet-stream' },\n        body: stream,\n        duplex: 'half',\n    });\n\n    /* Download the response body (it's a crc32 hash plus newline) */\n    const body = await r.body.getReader().read();\n\n    /* Make a crc32 comparison of the two (mind the newline in one!) */\n    const got = new TextDecoder().decode(body.value);\n\n    const want = crc32(array).toString(16);\n    if (got.toString().slice(0, -1) !== want.toString()) {\n        throw new Error(\"failed chunked test\");\n    }\n}\n\nasync function fixedCrc32Test(array) {\n    console.log(\"Making request with body size: \" + array.length);\n\n    /* Send it with content-length */\n    const res = await fetch(\"http://localhost:3000\", { keepalive: true, headers: { 'Content-Type': 'text/plain' }, method: \"POST\", body: array });\n\n    /* Download the response body (it's a crc32 hash plus newline) */\n    const body = await res.body.getReader().read();\n\n    /* Make a crc32 comparison of the two (mind the newline in one!) */\n    const got = new TextDecoder().decode(body.value);\n    const want = crc32(array).toString(16);\n    if (got.toString().slice(0, -1) !== want.toString()) {\n        throw new Error(\"failed test\");\n    }\n}\n\n/* Maximum chunk size is less than 256mb */\nconst sizes = [0, 0, 32, 32, 128, 256, 1024, 65536, 1024 * 1024, 1024 * 1024 * 128, 0, 0, 32, 32];\nfor (let i = 0; i < sizes.length; i++) {\n\n    /* Create buffer with random data */\n    const array = new Uint8Array(sizes[i]);\n    //if (sizes[i] <= 65536) {\n    //self.crypto.getRandomValues(array);\n    //} else {\n    array.fill(Math.random() * 255);\n    //}\n\n    /* Do this for all methods */\n    await fixedCrc32Test(array);\n    await chunkedCrc32Test(array);\n}\n\nconsole.log(\"Done!\");"
  }
]