11cb0ef41Sopenharmony_ci# llhttp 21cb0ef41Sopenharmony_ci[](https://github.com/nodejs/llhttp/actions?query=workflow%3ACI) 31cb0ef41Sopenharmony_ci 41cb0ef41Sopenharmony_ciPort of [http_parser][0] to [llparse][1]. 51cb0ef41Sopenharmony_ci 61cb0ef41Sopenharmony_ci## Why? 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ciLet's face it, [http_parser][0] is practically unmaintainable. Even 91cb0ef41Sopenharmony_ciintroduction of a single new method results in a significant code churn. 101cb0ef41Sopenharmony_ci 111cb0ef41Sopenharmony_ciThis project aims to: 121cb0ef41Sopenharmony_ci 131cb0ef41Sopenharmony_ci* Make it maintainable 141cb0ef41Sopenharmony_ci* Verifiable 151cb0ef41Sopenharmony_ci* Improving benchmarks where possible 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_ciMore details in [Fedor Indutny's talk at JSConf EU 2019](https://youtu.be/x3k_5Mi66sY) 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_ci## How? 201cb0ef41Sopenharmony_ci 211cb0ef41Sopenharmony_ciOver time, different approaches for improving [http_parser][0]'s code base 221cb0ef41Sopenharmony_ciwere tried. However, all of them failed due to resulting significant performance 231cb0ef41Sopenharmony_cidegradation. 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_ciThis project is a port of [http_parser][0] to TypeScript. [llparse][1] is used 261cb0ef41Sopenharmony_cito generate the output C source file, which could be compiled and 271cb0ef41Sopenharmony_cilinked with the embedder's program (like [Node.js][7]). 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_ci## Performance 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_ciSo far llhttp outperforms http_parser: 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_ci| | input size | bandwidth | reqs/sec | time | 341cb0ef41Sopenharmony_ci|:----------------|-----------:|-------------:|-----------:|--------:| 351cb0ef41Sopenharmony_ci| **llhttp** | 8192.00 mb | 1777.24 mb/s | 3583799.39 req/sec | 4.61 s | 361cb0ef41Sopenharmony_ci| **http_parser** | 8192.00 mb | 694.66 mb/s | 1406180.33 req/sec | 11.79 s | 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_cillhttp is faster by approximately **156%**. 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_ci## Maintenance 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_cillhttp project has about 1400 lines of TypeScript code describing the parser 431cb0ef41Sopenharmony_ciitself and around 450 lines of C code and headers providing the helper methods. 441cb0ef41Sopenharmony_ciThe whole [http_parser][0] is implemented in approximately 2500 lines of C, and 451cb0ef41Sopenharmony_ci436 lines of headers. 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ciAll optimizations and multi-character matching in llhttp are generated 481cb0ef41Sopenharmony_ciautomatically, and thus doesn't add any extra maintenance cost. On the contrary, 491cb0ef41Sopenharmony_cimost of http_parser's code is hand-optimized and unrolled. Instead describing 501cb0ef41Sopenharmony_ci"how" it should parse the HTTP requests/responses, a maintainer should 511cb0ef41Sopenharmony_ciimplement the new features in [http_parser][0] cautiously, considering 521cb0ef41Sopenharmony_cipossible performance degradation and manually optimizing the new code. 531cb0ef41Sopenharmony_ci 541cb0ef41Sopenharmony_ci## Verification 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_ciThe state machine graph is encoded explicitly in llhttp. The [llparse][1] 571cb0ef41Sopenharmony_ciautomatically checks the graph for absence of loops and correct reporting of the 581cb0ef41Sopenharmony_ciinput ranges (spans) like header names and values. In the future, additional 591cb0ef41Sopenharmony_cichecks could be performed to get even stricter verification of the llhttp. 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_ci## Usage 621cb0ef41Sopenharmony_ci 631cb0ef41Sopenharmony_ci```C 641cb0ef41Sopenharmony_ci#include "llhttp.h" 651cb0ef41Sopenharmony_ci 661cb0ef41Sopenharmony_cillhttp_t parser; 671cb0ef41Sopenharmony_cillhttp_settings_t settings; 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ci/* Initialize user callbacks and settings */ 701cb0ef41Sopenharmony_cillhttp_settings_init(&settings); 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_ci/* Set user callback */ 731cb0ef41Sopenharmony_cisettings.on_message_complete = handle_on_message_complete; 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ci/* Initialize the parser in HTTP_BOTH mode, meaning that it will select between 761cb0ef41Sopenharmony_ci * HTTP_REQUEST and HTTP_RESPONSE parsing automatically while reading the first 771cb0ef41Sopenharmony_ci * input. 781cb0ef41Sopenharmony_ci */ 791cb0ef41Sopenharmony_cillhttp_init(&parser, HTTP_BOTH, &settings); 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_ci/* Parse request! */ 821cb0ef41Sopenharmony_ciconst char* request = "GET / HTTP/1.1\r\n\r\n"; 831cb0ef41Sopenharmony_ciint request_len = strlen(request); 841cb0ef41Sopenharmony_ci 851cb0ef41Sopenharmony_cienum llhttp_errno err = llhttp_execute(&parser, request, request_len); 861cb0ef41Sopenharmony_ciif (err == HPE_OK) { 871cb0ef41Sopenharmony_ci /* Successfully parsed! */ 881cb0ef41Sopenharmony_ci} else { 891cb0ef41Sopenharmony_ci fprintf(stderr, "Parse error: %s %s\n", llhttp_errno_name(err), 901cb0ef41Sopenharmony_ci parser.reason); 911cb0ef41Sopenharmony_ci} 921cb0ef41Sopenharmony_ci``` 931cb0ef41Sopenharmony_ciFor more information on API usage, please refer to [src/native/api.h](https://github.com/nodejs/llhttp/blob/main/src/native/api.h). 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ci## Build Instructions 961cb0ef41Sopenharmony_ci 971cb0ef41Sopenharmony_ciMake sure you have [Node.js](https://nodejs.org/), npm and npx installed. Then under project directory run: 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_ci```sh 1001cb0ef41Sopenharmony_cinpm install 1011cb0ef41Sopenharmony_cimake 1021cb0ef41Sopenharmony_ci``` 1031cb0ef41Sopenharmony_ci 1041cb0ef41Sopenharmony_ci--- 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_ci### Bindings to other languages 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci* Python: [pallas/pyllhttp][8] 1091cb0ef41Sopenharmony_ci* Ruby: [metabahn/llhttp][9] 1101cb0ef41Sopenharmony_ci* Rust: [JackLiar/rust-llhttp][10] 1111cb0ef41Sopenharmony_ci 1121cb0ef41Sopenharmony_ci### Using with CMake 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_ciIf you want to use this library in a CMake project you can use the snippet below. 1151cb0ef41Sopenharmony_ci 1161cb0ef41Sopenharmony_ci``` 1171cb0ef41Sopenharmony_ciFetchContent_Declare(llhttp 1181cb0ef41Sopenharmony_ci URL "https://github.com/nodejs/llhttp/archive/refs/tags/v6.0.5.tar.gz") # Using version 6.0.5 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_ciFetchContent_MakeAvailable(llhttp) 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_citarget_link_libraries(${EXAMPLE_PROJECT_NAME} ${PROJECT_LIBRARIES} llhttp ${PROJECT_NAME}) 1231cb0ef41Sopenharmony_ci``` 1241cb0ef41Sopenharmony_ci 1251cb0ef41Sopenharmony_ci## Building on Windows 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_ci### Installation 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_ci* `choco install git` 1301cb0ef41Sopenharmony_ci* `choco install node` 1311cb0ef41Sopenharmony_ci* `choco install llvm` (or install the `C++ Clang tools for Windows` optional package from the Visual Studio 2019 installer) 1321cb0ef41Sopenharmony_ci* `choco install make` (or if you have MinGW, it comes bundled) 1331cb0ef41Sopenharmony_ci 1341cb0ef41Sopenharmony_ci1. Ensure that `Clang` and `make` are in your system path. 1351cb0ef41Sopenharmony_ci2. Using Git Bash, clone the repo to your preferred location. 1361cb0ef41Sopenharmony_ci3. Cd into the cloned directory and run `npm install` 1371cb0ef41Sopenharmony_ci5. Run `make` 1381cb0ef41Sopenharmony_ci6. Your `repo/build` directory should now have `libllhttp.a` and `libllhttp.so` static and dynamic libraries. 1391cb0ef41Sopenharmony_ci7. 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`. 1401cb0ef41Sopenharmony_ci 1411cb0ef41Sopenharmony_ci### A simple example on linking with the library: 1421cb0ef41Sopenharmony_ci 1431cb0ef41Sopenharmony_ciAssuming 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`. 1441cb0ef41Sopenharmony_ci 1451cb0ef41Sopenharmony_ciIf 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`. 1461cb0ef41Sopenharmony_ci 1471cb0ef41Sopenharmony_ci#### LICENSE 1481cb0ef41Sopenharmony_ci 1491cb0ef41Sopenharmony_ciThis software is licensed under the MIT License. 1501cb0ef41Sopenharmony_ci 1511cb0ef41Sopenharmony_ciCopyright Fedor Indutny, 2018. 1521cb0ef41Sopenharmony_ci 1531cb0ef41Sopenharmony_ciPermission is hereby granted, free of charge, to any person obtaining a 1541cb0ef41Sopenharmony_cicopy of this software and associated documentation files (the 1551cb0ef41Sopenharmony_ci"Software"), to deal in the Software without restriction, including 1561cb0ef41Sopenharmony_ciwithout limitation the rights to use, copy, modify, merge, publish, 1571cb0ef41Sopenharmony_cidistribute, sublicense, and/or sell copies of the Software, and to permit 1581cb0ef41Sopenharmony_cipersons to whom the Software is furnished to do so, subject to the 1591cb0ef41Sopenharmony_cifollowing conditions: 1601cb0ef41Sopenharmony_ci 1611cb0ef41Sopenharmony_ciThe above copyright notice and this permission notice shall be included 1621cb0ef41Sopenharmony_ciin all copies or substantial portions of the Software. 1631cb0ef41Sopenharmony_ci 1641cb0ef41Sopenharmony_ciTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 1651cb0ef41Sopenharmony_ciOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1661cb0ef41Sopenharmony_ciMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 1671cb0ef41Sopenharmony_ciNO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 1681cb0ef41Sopenharmony_ciDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 1691cb0ef41Sopenharmony_ciOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 1701cb0ef41Sopenharmony_ciUSE OR OTHER DEALINGS IN THE SOFTWARE. 1711cb0ef41Sopenharmony_ci 1721cb0ef41Sopenharmony_ci[0]: https://github.com/nodejs/http-parser 1731cb0ef41Sopenharmony_ci[1]: https://github.com/nodejs/llparse 1741cb0ef41Sopenharmony_ci[2]: https://en.wikipedia.org/wiki/Register_allocation#Spilling 1751cb0ef41Sopenharmony_ci[3]: https://en.wikipedia.org/wiki/Tail_call 1761cb0ef41Sopenharmony_ci[4]: https://llvm.org/docs/LangRef.html 1771cb0ef41Sopenharmony_ci[5]: https://llvm.org/docs/LangRef.html#call-instruction 1781cb0ef41Sopenharmony_ci[6]: https://clang.llvm.org/ 1791cb0ef41Sopenharmony_ci[7]: https://github.com/nodejs/node 1801cb0ef41Sopenharmony_ci[8]: https://github.com/pallas/pyllhttp 1811cb0ef41Sopenharmony_ci[9]: https://github.com/metabahn/llhttp 1821cb0ef41Sopenharmony_ci[10]: https://github.com/JackLiar/rust-llhttp 183