{"id":13528333,"url":"https://github.com/nodejs/llhttp","last_synced_at":"2025-05-14T03:09:50.057Z","repository":{"id":37822169,"uuid":"122002958","full_name":"nodejs/llhttp","owner":"nodejs","description":"Port of http_parser to llparse","archived":false,"fork":false,"pushed_at":"2025-05-05T16:33:59.000Z","size":7582,"stargazers_count":1755,"open_issues_count":10,"forks_count":196,"subscribers_count":41,"default_branch":"main","last_synced_at":"2025-05-08T12:30:28.555Z","etag":null,"topics":["http-parser","llparse","llvm"],"latest_commit_sha":null,"homepage":"http://llhttp.org","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nodejs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-02-19T00:12:53.000Z","updated_at":"2025-05-06T08:19:30.000Z","dependencies_parsed_at":"2023-10-03T21:53:38.525Z","dependency_job_id":"1fe98f32-e6ea-451e-a704-063407dd5c5d","html_url":"https://github.com/nodejs/llhttp","commit_stats":{"total_commits":467,"total_committers":55,"mean_commits":8.49090909090909,"dds":0.449678800856531,"last_synced_commit":"8371b40077c0177d743bb3dfed7e2b56cba18328"},"previous_names":["indutny/llhttp"],"tags_count":111,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nodejs%2Fllhttp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nodejs%2Fllhttp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nodejs%2Fllhttp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nodejs%2Fllhttp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nodejs","download_url":"https://codeload.github.com/nodejs/llhttp/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253831835,"owners_count":21971166,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["http-parser","llparse","llvm"],"created_at":"2024-08-01T06:02:26.167Z","updated_at":"2025-05-14T03:09:49.962Z","avatar_url":"https://github.com/nodejs.png","language":"TypeScript","readme":"# llhttp\n[![CI](https://github.com/nodejs/llhttp/workflows/CI/badge.svg)](https://github.com/nodejs/llhttp/actions?query=workflow%3ACI)\n\nPort of [http_parser][0] to [llparse][1].\n\n## Why?\n\nLet's face it, [http_parser][0] is practically unmaintainable. Even\nintroduction of a single new method results in a significant code churn.\n\nThis project aims to:\n\n* Make it maintainable\n* Verifiable\n* Improving benchmarks where possible\n\nMore details in [Fedor Indutny's talk at JSConf EU 2019](https://youtu.be/x3k_5Mi66sY)\n\n## How?\n\nOver time, different approaches for improving [http_parser][0]'s code base\nwere tried. However, all of them failed due to resulting significant performance\ndegradation.\n\nThis project is a port of [http_parser][0] to TypeScript. [llparse][1] is used\nto generate the output C source file, which could be compiled and\nlinked with the embedder's program (like [Node.js][7]).\n\n## Performance\n\nSo far llhttp outperforms http_parser:\n\n|                 | input size |  bandwidth   |  reqs/sec  |   time  |\n|:----------------|-----------:|-------------:|-----------:|--------:|\n| **llhttp**      | 8192.00 mb | 1777.24 mb/s | 3583799.39 req/sec | 4.61 s |\n| **http_parser** | 8192.00 mb | 694.66 mb/s | 1406180.33 req/sec | 11.79 s |\n\nllhttp is faster by approximately **156%**.\n\n## Maintenance\n\nllhttp project has about 1400 lines of TypeScript code describing the parser\nitself and around 450 lines of C code and headers providing the helper methods.\nThe whole [http_parser][0] is implemented in approximately 2500 lines of C, and\n436 lines of headers.\n\nAll optimizations and multi-character matching in llhttp are generated\nautomatically, and thus doesn't add any extra maintenance cost. On the contrary,\nmost of http_parser's code is hand-optimized and unrolled. Instead describing\n\"how\" it should parse the HTTP requests/responses, a maintainer should\nimplement the new features in [http_parser][0] cautiously, considering\npossible performance degradation and manually optimizing the new code.\n\n## Verification\n\nThe state machine graph is encoded explicitly in llhttp. The [llparse][1]\nautomatically checks the graph for absence of loops and correct reporting of the\ninput ranges (spans) like header names and values. In the future, additional\nchecks could be performed to get even stricter verification of the llhttp.\n\n## Usage\n\n```C\n#include \"stdio.h\"\n#include \"llhttp.h\"\n#include \"string.h\"\n\nint handle_on_message_complete(llhttp_t* parser) {\n\tfprintf(stdout, \"Message completed!\\n\");\n\treturn 0;\n}\n\nint main() {\n\tllhttp_t parser;\n\tllhttp_settings_t settings;\n\n\t/*Initialize user callbacks and settings */\n\tllhttp_settings_init(\u0026settings);\n\n\t/*Set user callback */\n\tsettings.on_message_complete = handle_on_message_complete;\n\n\t/*Initialize the parser in HTTP_BOTH mode, meaning that it will select between\n\t*HTTP_REQUEST and HTTP_RESPONSE parsing automatically while reading the first\n\t*input.\n\t*/\n\tllhttp_init(\u0026parser, HTTP_BOTH, \u0026settings);\n\n\t/*Parse request! */\n\tconst char* request = \"GET / HTTP/1.1\\r\\n\\r\\n\";\n\tint request_len = strlen(request);\n\n\tenum llhttp_errno err = llhttp_execute(\u0026parser, request, request_len);\n\tif (err == HPE_OK) {\n\t\tfprintf(stdout, \"Successfully parsed!\\n\");\n\t} else {\n\t\tfprintf(stderr, \"Parse error: %s %s\\n\", llhttp_errno_name(err), llhttp_get_error_reason(\u0026parser));\n\t}\n}\n```\nFor more information on API usage, please refer to [src/native/api.h](https://github.com/nodejs/llhttp/blob/main/src/native/api.h).\n\n## API\n\n### llhttp_settings_t\n\nThe settings object contains a list of callbacks that the parser will invoke.\n\nThe following callbacks can return `0` (proceed normally), `-1` (error) or `HPE_PAUSED` (pause the parser):\n\n* `on_message_begin`: Invoked when a new request/response starts.\n* `on_message_complete`: Invoked when a request/response has been completedly parsed.\n* `on_url_complete`: Invoked after the URL has been parsed.\n* `on_method_complete`: Invoked after the HTTP method has been parsed.\n* `on_protocol_complete`: Invoked after the HTTP version has been parsed.\n* `on_version_complete`: Invoked after the HTTP version has been parsed.\n* `on_status_complete`: Invoked after the status code has been parsed.\n* `on_header_field_complete`: Invoked after a header name has been parsed.\n* `on_header_value_complete`: Invoked after a header value has been parsed.\n* `on_chunk_header`: Invoked after a new chunk is started. The current chunk length is stored in `parser-\u003econtent_length`.\n* `on_chunk_extension_name_complete`: Invoked after a chunk extension name is started.\n* `on_chunk_extension_value_complete`: Invoked after a chunk extension value is started.\n* `on_chunk_complete`: Invoked after a new chunk is received. \n* `on_reset`: Invoked after `on_message_complete` and before `on_message_begin` when a new message \n   is received on the same parser. This is not invoked for the first message of the parser.\n\nThe following callbacks can return `0` (proceed normally), `-1` (error) or `HPE_USER` (error from the callback): \n\n* `on_url`: Invoked when another character of the URL is received. \n* `on_status`: Invoked when another character of the status is received.\n* `on_method`: Invoked when another character of the method is received. \n   When parser is created with `HTTP_BOTH` and the input is a response, this also invoked for the sequence `HTTP/`\n   of the first message.\n* `on_protocol`: Invoked when another character of the protocol is received.\n* `on_version`: Invoked when another character of the version is received.\n* `on_header_field`: Invoked when another character of a header name is received.\n* `on_header_value`: Invoked when another character of a header value is received.\n* `on_chunk_extension_name`: Invoked when another character of a chunk extension name is received.\n* `on_chunk_extension_value`: Invoked when another character of a extension value is received.\n\nThe callback `on_headers_complete`, invoked when headers are completed, can return:\n\n* `0`: Proceed normally.\n* `1`: Assume that request/response has no body, and proceed to parsing the next message.\n* `2`: Assume absence of body (as above) and make `llhttp_execute()` return `HPE_PAUSED_UPGRADE`.\n* `-1`: Error\n* `HPE_PAUSED`: Pause the parser.\n\n### `void llhttp_init(llhttp_t* parser, llhttp_type_t type, const llhttp_settings_t* settings)`\n\nInitialize the parser with specific type and user settings.\n\n### `uint8_t llhttp_get_type(llhttp_t* parser)`\n\nReturns the type of the parser.\n\n### `uint8_t llhttp_get_http_major(llhttp_t* parser)`\n\nReturns the major version of the HTTP protocol of the current request/response.\n\n### `uint8_t llhttp_get_http_minor(llhttp_t* parser)`\n\nReturns the minor version of the HTTP protocol of the current request/response.\n\n### `uint8_t llhttp_get_method(llhttp_t* parser)`\n\nReturns the method of the current request.\n\n### `int llhttp_get_status_code(llhttp_t* parser)`\n\nReturns the method of the current response.\n\n### `uint8_t llhttp_get_upgrade(llhttp_t* parser)`\n\nReturns `1` if request includes the `Connection: upgrade` header.\n\n### `void llhttp_reset(llhttp_t* parser)`\n\nReset an already initialized parser back to the start state, preserving the \nexisting parser type, callback settings, user data, and lenient flags.\n\n### `void llhttp_settings_init(llhttp_settings_t* settings)`\n\nInitialize the settings object.\n\n### `llhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len)`\n\nParse full or partial request/response, invoking user callbacks along the way.\n\nIf any of `llhttp_data_cb` returns errno not equal to `HPE_OK` - the parsing interrupts, \nand such errno is returned from `llhttp_execute()`. If `HPE_PAUSED` was used as a errno, \nthe execution can be resumed with `llhttp_resume()` call. In that case the input should be advanced \nto the last processed byte from the parser, which can be obtained via `llhttp_get_error_pos()`.\n\nIn a special case of CONNECT/Upgrade request/response `HPE_PAUSED_UPGRADE` is returned \nafter fully parsing the request/response. If the user wishes to continue parsing, \nthey need to invoke `llhttp_resume_after_upgrade()`.\n\n**if this function ever returns a non-pause type error, it will continue to return \nthe same error upon each successive call up until `llhttp_init()` is called.**\n\nIf this function returns `HPE_OK`, it means all the input has been consumed and parsed.\n\n### `llhttp_errno_t llhttp_finish(llhttp_t* parser)`\n\nThis method should be called when the other side has no further bytes to\nsend (e.g. shutdown of readable side of the TCP connection.)\n\nRequests without `Content-Length` and other messages might require treating\nall incoming bytes as the part of the body, up to the last byte of the\nconnection. \n\nThis method will invoke `on_message_complete()` callback if the\nrequest was terminated safely. Otherwise a error code would be returned.\n\n\n### `int llhttp_message_needs_eof(const llhttp_t* parser)`\n\nReturns `1` if the incoming message is parsed until the last byte, and has to be completed by calling `llhttp_finish()` on EOF.\n\n### `int llhttp_should_keep_alive(const llhttp_t* parser)`\n\nReturns `1` if there might be any other messages following the last that was\nsuccessfully parsed.\n\n### `void llhttp_pause(llhttp_t* parser)`\n\nMake further calls of `llhttp_execute()` return `HPE_PAUSED` and set\nappropriate error reason.\n\n**Do not call this from user callbacks! User callbacks must return\n`HPE_PAUSED` if pausing is required.**\n\n### `void llhttp_resume(llhttp_t* parser)`\n\nMight be called to resume the execution after the pause in user's callback.\n\nSee `llhttp_execute()` above for details.\n\n**Call this only if `llhttp_execute()` returns `HPE_PAUSED`.**\n\n### `void llhttp_resume_after_upgrade(llhttp_t* parser)`\n\nMight be called to resume the execution after the pause in user's callback.\nSee `llhttp_execute()` above for details.\n\n**Call this only if `llhttp_execute()` returns `HPE_PAUSED_UPGRADE`**\n\n### `llhttp_errno_t llhttp_get_errno(const llhttp_t* parser)`\n\nReturns the latest error.\n\n### `const char* llhttp_get_error_reason(const llhttp_t* parser)`\n\nReturns the verbal explanation of the latest returned error.\n\n**User callback should set error reason when returning the error. See\n`llhttp_set_error_reason()` for details.**\n\n### `void llhttp_set_error_reason(llhttp_t* parser, const char* reason)`\n\nAssign verbal description to the returned error. Must be called in user\ncallbacks right before returning the errno.\n\n**`HPE_USER` error code might be useful in user callbacks.**\n\n### `const char* llhttp_get_error_pos(const llhttp_t* parser)`\n\nReturns the pointer to the last parsed byte before the returned error. The\npointer is relative to the `data` argument of `llhttp_execute()`.\n\n**This method might be useful for counting the number of parsed bytes.**\n\n### `const char* llhttp_errno_name(llhttp_errno_t err)`\n\nReturns textual name of error code.\n\n### `const char* llhttp_method_name(llhttp_method_t method)`\n\nReturns textual name of HTTP method.\n\n### `const char* llhttp_status_name(llhttp_status_t status)`\n\nReturns textual name of HTTP status.\n\n### `void llhttp_set_lenient_headers(llhttp_t* parser, int enabled)`\n\nEnables/disables lenient header value parsing (disabled by default).\nLenient parsing disables header value token checks, extending llhttp's\nprotocol support to highly non-compliant clients/server. \n\nNo `HPE_INVALID_HEADER_TOKEN` will be raised for incorrect header values when\nlenient parsing is \"on\".\n\n**Enabling this flag can pose a security issue since you will be exposed to request smuggling attacks. USE WITH CAUTION!**\n\n### `void llhttp_set_lenient_chunked_length(llhttp_t* parser, int enabled)`\n\nEnables/disables lenient handling of conflicting `Transfer-Encoding` and\n`Content-Length` headers (disabled by default).\n\nNormally `llhttp` would error when `Transfer-Encoding` is present in\nconjunction with `Content-Length`. \n\nThis error is important to prevent HTTP request smuggling, but may be less desirable\nfor small number of cases involving legacy servers.\n\n**Enabling this flag can pose a security issue since you will be exposed to request smuggling attacks. USE WITH CAUTION!**\n\n### `void llhttp_set_lenient_keep_alive(llhttp_t* parser, int enabled)`\n\nEnables/disables lenient handling of `Connection: close` and HTTP/1.0\nrequests responses.\n\nNormally `llhttp` would error the HTTP request/response \nafter the request/response with `Connection: close` and `Content-Length`. \n\nThis is important to prevent cache poisoning attacks,\nbut might interact badly with outdated and insecure clients. \n\nWith this flag the extra request/response will be parsed normally.\n\n**Enabling this flag can pose a security issue since you will be exposed to poisoning attacks. USE WITH CAUTION!**\n\n### `void llhttp_set_lenient_transfer_encoding(llhttp_t* parser, int enabled)`\n\nEnables/disables lenient handling of `Transfer-Encoding` header.\n\nNormally `llhttp` would error when a `Transfer-Encoding` has `chunked` value\nand another value after it (either in a single header or in multiple\nheaders whose value are internally joined using `, `).\n\nThis is mandated by the spec to reliably determine request body size and thus\navoid request smuggling.\n\nWith this flag the extra value will be parsed normally.\n\n**Enabling this flag can pose a security issue since you will be exposed to request smuggling attacks. USE WITH CAUTION!**\n\n### `void llhttp_set_lenient_version(llhttp_t* parser, int enabled)`\n\nEnables/disables lenient handling of HTTP version.\n\nNormally `llhttp` would error when the HTTP version in the request or status line\nis not `0.9`, `1.0`, `1.1` or `2.0`.\nWith this flag the extra value will be parsed normally.\n\n**Enabling this flag can pose a security issue since you will allow unsupported HTTP versions. USE WITH CAUTION!**\n\n### `void llhttp_set_lenient_data_after_close(llhttp_t* parser, int enabled)`\n\nEnables/disables lenient handling of additional data received after a message ends\nand keep-alive is disabled.\n\nNormally `llhttp` would error when additional unexpected data is received if the message\ncontains the `Connection` header with `close` value.\nWith this flag the extra data will discarded without throwing an error.\n\n**Enabling this flag can pose a security issue since you will be exposed to poisoning attacks. USE WITH CAUTION!**\n\n### `void llhttp_set_lenient_optional_lf_after_cr(llhttp_t* parser, int enabled)`\n\nEnables/disables lenient handling of incomplete CRLF sequences.\n\nNormally `llhttp` would error when a CR is not followed by LF when terminating the\nrequest line, the status line, the headers or a chunk header.\nWith this flag only a CR is required to terminate such sections.\n\n**Enabling this flag can pose a security issue since you will be exposed to request smuggling attacks. USE WITH CAUTION!**\n\n### `void llhttp_set_lenient_optional_cr_before_lf(llhttp_t* parser, int enabled)`\n\nEnables/disables lenient handling of line separators.\n\nNormally `llhttp` would error when a LF is not preceded by CR when terminating the\nrequest line, the status line, the headers, a chunk header or a chunk data.\nWith this flag only a LF is required to terminate such sections.\n\n**Enabling this flag can pose a security issue since you will be exposed to request smuggling attacks. USE WITH CAUTION!**\n\n### `void llhttp_set_lenient_optional_crlf_after_chunk(llhttp_t* parser, int enabled)`\n\nEnables/disables lenient handling of chunks not separated via CRLF.\n\nNormally `llhttp` would error when after a chunk data a CRLF is missing before\nstarting a new chunk.\nWith this flag the new chunk can start immediately after the previous one.\n\n**Enabling this flag can pose a security issue since you will be exposed to request smuggling attacks. USE WITH CAUTION!**\n\n### `void llhttp_set_lenient_spaces_after_chunk_size(llhttp_t* parser, int enabled)`\n\nEnables/disables lenient handling of spaces after chunk size.\n\nNormally `llhttp` would error when after a chunk size is followed by one or more spaces are present instead of a CRLF or `;`.\nWith this flag this check is disabled.\n\n**Enabling this flag can pose a security issue since you will be exposed to request smuggling attacks. USE WITH CAUTION!**\n\n## Build Instructions\n\nMake sure you have [Node.js](https://nodejs.org/), npm and npx installed. Then under project directory run:\n\n```sh\nnpm ci\nmake\n```\n\n---\n\n### Bindings to other languages\n\n* Lua: [MunifTanjim/llhttp.lua][11]\n* Python: [pallas/pyllhttp][8]\n* Ruby: [metabahn/llhttp][9]\n* Rust: [JackLiar/rust-llhttp][10]\n\n### Using with CMake\n\nIf you want to use this library in a CMake project as a shared library, you can use the snippet below.\n\n```\nFetchContent_Declare(llhttp\n  URL \"https://github.com/nodejs/llhttp/archive/refs/tags/release/v8.1.0.tar.gz\")\n\nFetchContent_MakeAvailable(llhttp)\n\n# Link with the llhttp_shared target\ntarget_link_libraries(${EXAMPLE_PROJECT_NAME} ${PROJECT_LIBRARIES} llhttp_shared ${PROJECT_NAME})\n```\n\nIf you want to use this library in a CMake project as a static library, you can set some cache variables first.\n\n```\nFetchContent_Declare(llhttp\n  URL \"https://github.com/nodejs/llhttp/archive/refs/tags/release/v8.1.0.tar.gz\")\n\nset(BUILD_SHARED_LIBS OFF CACHE INTERNAL \"\")\nset(BUILD_STATIC_LIBS ON CACHE INTERNAL \"\")\nFetchContent_MakeAvailable(llhttp)\n\n# Link with the llhttp_static target\ntarget_link_libraries(${EXAMPLE_PROJECT_NAME} ${PROJECT_LIBRARIES} llhttp_static ${PROJECT_NAME})\n```\n\n_Note that using the git repo directly (e.g., via a git repo url and tag) will not work with FetchContent_Declare because [CMakeLists.txt](./CMakeLists.txt) requires string replacements (e.g., `_RELEASE_`) before it will build._\n\n## Building on Windows\n\n### Installation\n\n* `choco install git`\n* `choco install node`\n* `choco install llvm` (or install the `C++ Clang tools for Windows` optional package from the Visual Studio 2019 installer)\n* `choco install make` (or if you have MinGW, it comes bundled)\n\n1. Ensure that `Clang` and `make` are in your system path.\n2. Using Git Bash, clone the repo to your preferred location.\n3. Cd into the cloned directory and run `npm ci`\n5. Run `make`\n6. Your `repo/build` directory should now have `libllhttp.a` and `libllhttp.so` static and dynamic libraries.\n7. When building your executable, you can link to these libraries. Make sure to set the build folder as an include path when building so you can reference the declarations in `repo/build/llhttp.h`.\n\n### A simple example on linking with the library:\n\nAssuming you have an executable `main.cpp` in your current working directory, you would run: `clang++ -Os -g3 -Wall -Wextra -Wno-unused-parameter -I/path/to/llhttp/build main.cpp /path/to/llhttp/build/libllhttp.a -o main.exe`.\n\nIf you are getting `unresolved external symbol` linker errors you are likely attempting to build `llhttp.c` without linking it with object files from `api.c` and `http.c`.\n\n#### LICENSE\n\nThis software is licensed under the MIT License.\n\nCopyright Fedor Indutny, 2018.\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to permit\npersons to whom the Software is furnished to do so, subject to the\nfollowing conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\nOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\nNO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\nDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\nOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\nUSE OR OTHER DEALINGS IN THE SOFTWARE.\n\n[0]: https://github.com/nodejs/http-parser\n[1]: https://github.com/nodejs/llparse\n[2]: https://en.wikipedia.org/wiki/Register_allocation#Spilling\n[3]: https://en.wikipedia.org/wiki/Tail_call\n[4]: https://llvm.org/docs/LangRef.html\n[5]: https://llvm.org/docs/LangRef.html#call-instruction\n[6]: https://clang.llvm.org/\n[7]: https://github.com/nodejs/node\n[8]: https://github.com/pallas/pyllhttp\n[9]: https://github.com/metabahn/llhttp\n[10]: https://github.com/JackLiar/rust-llhttp\n[11]: https://github.com/MunifTanjim/llhttp.lua\n","funding_links":[],"categories":["TypeScript","Packages"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnodejs%2Fllhttp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnodejs%2Fllhttp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnodejs%2Fllhttp/lists"}